Files
compiler-explorer/etc/scripts/docenizers/docenizer-java.ts
Mats Jun Larsen 633eb82d18 Transition to ECMAScript Modules (#4780)
Makes the Compiler Explorer app, and all the tooling ESM compatible.
Things that have been done:

1. The package.json has `type: module` now
2. All relative imports have a .js ending
3. All directory imports are now directory/index.js to comply with ESM
standards
4. Dependency node-graceful is now imported into tree, because the
package is broken under esm
5. Dependency p-queue has been bumped to 7.x with ESM support
6. Dependency profanities has been bumped to 3.x with ESM support
7. Webpack config is now both ESM and CommonJS compatible
8. Non-ESM compatible imports have been rewritten
9. ESLint configuration has been tweaked to not fail on .js imports
10. Mocha is now hacked together and ran with ts-node-esm
11. Webpack is now hacked together and ran with ts-node-esm
12. Webpack config is now ESM compatible, so that it can be used in the
dev server
13. Cypress code still runs commonjs, and has been excluded from the
tsconfig
14. All sinon mock tests have been commented out, because sinon module
mocks do not work with ESModules (because ESModules are immutable)

A lot of tests are now giving warnings/errors to stdout, yet still pass.
Docenizer codegenerator scripts have been updated, but I did not re-run
them, and instead just changed their code.

---------

Co-authored-by: Matt Godbolt <matt@godbolt.org>
2023-02-27 18:06:38 -06:00

109 lines
4.3 KiB
JavaScript

#!/usr/bin/env node
import fs from 'fs/promises';
import * as cheerio from 'cheerio';
const JVMS_SPECIFICATION = './vendor/jvms.html';
const VARIADIC_MAPPINGS = {
'<n>': ['0', '1', '2', '3'],
'<d>': ['0', '1'],
'<f>': ['0, 1', '2'],
'<i>': ['m1', '0', '1', '2', '3', '4', '5'],
'<l>': ['0', '1'],
'<op>': ['g', 'l'],
'<cond>': ['eq', 'ne'],
};
type InstructionInfo = {
name: string
anchor: string
tooltip: string
format: string[]
stack: [string | null, string | null]
description: string
}
const extract = (node: cheerio.Cheerio<cheerio.Element>, $: cheerio.CheerioAPI) => {
const anchorElement = node.find('div.titlepage > div > div > h3.title > a[name*="jvms-6.5"]').first();
const nameElement = anchorElement.parent().find('span.emphasis > em');
const anchor = anchorElement.attr('name')!;
const name = nameElement.text();
const [
operationSection,
formatSection,
_formsSection,
operandStackSection,
descriptionSection,
] = node.find('div.section').toArray().map(it => $(it));
const operation = operationSection.find('p.norm').first().text();
const format = formatSection.find('div.literallayout > p > span.emphasis > em').toArray().map(it => $(it).text());
const description = descriptionSection.find('p.norm-dynamic').first();
// rewrite links to oracle.com
$(description).find('* > a[href*="jvms-"]').toArray().forEach((el) => {
$(el).attr('href', `https://docs.oracle.com/javase/specs/jvms/se18/html/${$(el).attr('href')}`);
});
const [stackBefore, stackAfter] = operandStackSection.find('p.norm')
.toArray()
.map(it => $(it));
const result: InstructionInfo[] = [];
const hasVariadicMapping = Object.keys(VARIADIC_MAPPINGS).some((pat) => name.endsWith(pat));
if (hasVariadicMapping) {
for (const [pattern, mappings] of Object.entries(VARIADIC_MAPPINGS)) {
if (name.endsWith(pattern)) {
for (const mapping of mappings) {
result.push({
name: name.replace(pattern, mapping).replaceAll('<', '[').replaceAll('>', ']'),
anchor,
description: description.html()!,
tooltip: operation,
stack: [stackBefore?.html(), stackAfter?.html()],
format: format.map(x => x.replaceAll('<', '[').replaceAll('>', ']')),
});
}
}
}
} else {
result.push({
name,
anchor,
description: description.html()!,
tooltip: operation,
stack: [stackBefore?.html(), stackAfter?.html()],
format,
});
}
return result;
};
const main = async () => {
const file = await fs.readFile(JVMS_SPECIFICATION, 'utf-8');
const $ = cheerio.load(file);
const sections = $('div.section-execution');
const instructions = sections.toArray()
.slice(1) // Drop 1 because the first is the "mne monic"
.map(it => extract($(it), $))
.flat();
console.log('import {AssemblyInstructionInfo} from \'../base.js\';');
console.log('');
console.log('export function getAsmOpcode(opcode: string | undefined): AssemblyInstructionInfo | undefined {');
console.log(' if (!opcode) return;');
console.log(' switch (opcode.toUpperCase()) {');
for (const instruction of instructions) {
console.log(` case '${instruction.name.toUpperCase()}':`);
console.log(' return {');
console.log(` url: \`https://docs.oracle.com/javase/specs/jvms/se18/html/jvms-6.html#${instruction.anchor}\`,`);
const body = `<p>Instruction ${instruction.name}: ${instruction.tooltip}</p><p>Format: ${instruction.format.join(' ')}</p>${instruction.stack[0] && `<p>Operand Stack: ${instruction.stack[0]} ${instruction.stack[1]}</p>`}<p>${instruction.description}</p>`;
console.log(` html: \`${body.replace(/\s\s+/g, ' ')}\`,`);
console.log(` tooltip: \`${instruction.tooltip.replace(/\s\s+/g, ' ')}\`,`);
console.log(' };');
}
console.log(' }');
console.log('}');
};
main().then(() =>{}).catch(e => console.error("Caught error", e));