UNPKG

@4qwerty7/sim-node

Version:

SIM is a code similarity test tool, sim-node is a wasm version.

96 lines (88 loc) 3.06 kB
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;