From cf207acc09547c3e389cebb1c2202e80cf4359e9 Mon Sep 17 00:00:00 2001 From: Dmitriy Date: Sun, 20 Jul 2025 17:49:31 +0300 Subject: [PATCH] Add normalize command to process and rewrite EO programs --- src/commands/normalize.js | 68 +++++++++++++++++++++++++++++++++++++++ src/eoc.js | 17 +++++++++- 2 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 src/commands/normalize.js diff --git a/src/commands/normalize.js b/src/commands/normalize.js new file mode 100644 index 00000000..50daf66f --- /dev/null +++ b/src/commands/normalize.js @@ -0,0 +1,68 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2022-2025 Objectionary.com + * SPDX-License-Identifier: MIT + */ + +const fs = require('fs'); +const path = require('path'); +const { spawnSync } = require('child_process'); +const parse = require('./parse'); +const print = require('./print'); + +module.exports = async function normalize(opts) { + const target = path.resolve(opts.target || '.'); + const eocDir = path.join(target, '.eoc'); + const normalizedDir = path.join(eocDir, 'normalized'); + + if (!fs.existsSync(eocDir)) { + throw new Error(`No .eoc/ directory found at ${eocDir}. Run "eoc parse" first.`); + } + + // Step 1: parse EO files to XMIR + await parse({ target }); + + // Step 2: make sure .eoc/normalized exists + if (!fs.existsSync(normalizedDir)) { + fs.mkdirSync(normalizedDir, { recursive: true }); + } + + // Step 3: process all .xmir files + const files = fs.readdirSync(eocDir).filter(f => f.endsWith('.xmir')); + for (const file of files) { + const base = path.basename(file, '.xmir'); + const inputXmir = path.join(eocDir, file); + const phi = path.join(eocDir, `${base}.phi`); + const normalizedPhi = path.join(eocDir, `${base}.norm.phi`); + const normalizedXmir = path.join(normalizedDir, `${base}.xmir`); + + // xmir -> phi + runPhino(['translate', inputXmir], phi); + + // phi -> normalized.phi + runPhino(['rewrite', '--normalize', phi], normalizedPhi); + + // normalized.phi -> xmir + runPhino(['translate', '--reverse', normalizedPhi], normalizedXmir); + } + + // Step 4: print .xmir -> .eo + await print({ + target, + printInput: '.eoc/normalized', + printOutput: '.eoc/normalized' + }); + + console.info(`Normalized EO sources saved to ${path.relative(process.cwd(), normalizedDir)}`); +}; + +function runPhino(args, outputFilePath) { + const phinoJar = path.resolve(__dirname, '../../phino.jar'); // ← путь до JAR-файла Phino + const javaArgs = ['-jar', phinoJar].concat(args); + const result = spawnSync('java', javaArgs, { encoding: 'utf-8' }); + + if (result.status !== 0) { + throw new Error(`Phino failed:\n${result.stderr}`); + } + + fs.writeFileSync(outputFilePath, result.stdout); +} diff --git a/src/eoc.js b/src/eoc.js index e9577f60..d741d1d9 100755 --- a/src/eoc.js +++ b/src/eoc.js @@ -32,6 +32,7 @@ const {program} = require('commander'), generate_comments: require('./commands/generate_comments'), jeo_disassemble: require('./commands/jeo/disassemble'), jeo_assemble: require('./commands/jeo/assemble'), + normalize: require('./commands/normalize'), latex: require('./commands/latex') }, commands = { @@ -58,7 +59,7 @@ const {program} = require('commander'), } } }; - + if (process.argv.includes('--verbose')) { tinted.enable('debug'); console.debug('Debug output is turned ON'); @@ -112,6 +113,20 @@ program.command('audit') coms().audit(program.opts()); }); +program.command('normalize') + .description('Normalize EO programs by rewriting their .phi representation') + .action((str, opts) => { + clear(str); + if (program.opts().alone === undefined) { + coms().register(program.opts()) + .then(() => coms().parse(program.opts())) + .then(() => coms().normalize({...program.opts(), ...str})); + } else { + coms().normalize({...program.opts(), ...str}); + } + }); + + program.command('foreign') .description('Inspect and print the list of foreign objects') .action((str, opts) => {