@4qwerty7/sim-node
Version:
SIM is a code similarity test tool, sim-node is a wasm version.
96 lines (88 loc) • 3.06 kB
JavaScript
const fs = require('fs');
const fsp = fs.promises;
const vm = require('vm');
const path = require('path');
const supportedTypes = ['8086', 'c', 'c++', 'java', 'lisp', 'm2', 'mira', 'pasc', 'text'];
const files = {};
async function initFile() {
let tasks = [];
for (const type of supportedTypes) {
let obj = { js: null, wasm: null, script: null };
files[type] = obj;
tasks.push(async () => {
const filename = path.join(__dirname, `sim_${type}.js`);
obj.js = await fsp.readFile(filename, 'utf-8');
obj.script = new vm.Script(obj.js, { filename });
});
tasks.push(async () => {
obj.wasm = await fsp.readFile(path.join(__dirname, `sim_${type}.wasm`));
});
}
await Promise.all(tasks.map(x => x()));
}
const fileInitTask = initFile();
async function enterModuleEnvironment(type, callback) {
await fileInitTask;
let module = {};
let ret = undefined;
let onQuit;
let promise = new Promise(resolve => onQuit = resolve);
let context = { require, __dirname, process: { on() {}, exit() { onQuit() }, argv: [] }, module, Module: {
quit() { onQuit(); },
outputs: [],
getOutputs() {
return context.Module.outputs.map(out => Buffer.from(out).toString());
},
preRun() {
let out = [];
let err = [];
context.Module.outputs.push(out, err);
context.Module.FS.init(() => null, c => out.push(c), c => err.push(c));
},
wasmBinary: files[type].wasm,
print() {},
printErr() {},
onRuntimeInitialized() {
ret = callback(context.Module);
}
} };
vm.createContext(context);
files[type].script.runInContext(context);
await promise;
return ret;
}
async function sim(type, codes) {
let nameCodeMap = codes;
if (!(codes instanceof Map)) {
if (!Array.isArray(codes)) codes = Object.entries(codes);
nameCodeMap = new Map(codes);
}
let names = Array.from(nameCodeMap.keys());
let filenames = names.map((_, idx) => idx + '.' + type);
let err = null;
let content = await enterModuleEnvironment(type, Module => {
const FS = Module.FS;
names.forEach((name, idx) => {
FS.writeFile(filenames[idx], nameCodeMap.get(name));
});
try {
Module.callMain(['-p', ...filenames]);
} catch (e) {
err = e;
}
return Module.getOutputs();
}).catch(e => err = e);
err = err || (content && content[1]);
if (err) throw err; // reject by reason
const diffs = content[0].split('\n').map(x => x.trim()).filter(x => x.includes(' consists for ') && x.includes(' % of ') && x.endsWith(' material')).map(x => x.replace(' consists for ', '|').replace(' % of ', '|').replace(' material', '').split('|'));
const ret = [];
function nameFromFile(file) {
return names[parseInt(file.split('.')[0])];
}
for (const [a, pre, b] of diffs) {
ret.push([nameFromFile(a), nameFromFile(b), parseFloat(pre)]);
}
return ret;
}
sim.supportedTypes = supportedTypes;
module.exports = sim;