uppaal-to-tchecker
Version:
JavaScript implementation of Uppaal to TChecker translator - convert Uppaal timed automata models to TChecker format
183 lines (154 loc) • 5.72 kB
JavaScript
/**
* CLI interface for uppaal-to-tchecker
* JavaScript implementation of utot.cpp
*/
const { Command } = require('commander');
const chalk = require('chalk');
const fs = require('fs').promises;
const path = require('path');
const UppaalToTChecker = require('../src/index');
const { UTOTException } = require('../src/exceptions');
const program = new Command();
// Package version
const packageJson = require('../package.json');
program
.name('utot')
.description('Translate Uppaal models to TChecker format')
.version(packageJson.version)
.argument('[input-file]', 'Uppaal input file (stdin if not specified)')
.argument('[output-file]', 'TChecker output file (stdout if not specified)')
.option('-d, --debug', 'enable debug traces')
.option('-e, --erase', 'erase output file if it exists')
.option('-V, --verbose', 'increase the level of verbosity', (value, previous) => previous + 1, 0)
.option('--xml', 'enforce XML as input format')
.option('--xta', 'enforce XTA as input language')
.option('--ta', 'enforce TA as input language')
.option('--sysname <id>', 'specify the label of the system')
.helpOption('-h, --help', 'display this help message');
program.parse();
const options = program.opts();
const args = program.args;
async function main() {
try {
const translator = new UppaalToTChecker();
// Set options
translator.setVerbose(options.verbose);
translator.setDebug(options.debug);
// Determine input and output
const inputFile = args[0];
const outputFile = args[1];
// Build translation options
const translateOptions = {
verbose: options.verbose,
debug: options.debug
};
// Set format and language
if (options.xml) {
translateOptions.format = 'xml';
translateOptions.language = 'xta';
} else if (options.xta) {
translateOptions.format = 'xta';
translateOptions.language = 'xta';
} else if (options.ta) {
translateOptions.format = 'xta';
translateOptions.language = 'ta';
}
// Set system name
if (options.sysname) {
translateOptions.systemName = options.sysname;
}
let result;
if (inputFile) {
// Check if output file exists and handle erase option
if (outputFile && !options.erase) {
try {
await fs.access(outputFile);
console.error(chalk.red(`Output file '${outputFile}' already exists. Use -e to overwrite.`));
process.exit(1);
} catch (error) {
// File doesn't exist, continue
}
}
// Translate file
result = await translator.translateFile(inputFile, outputFile, translateOptions);
// Print to stdout if no output file specified
if (!outputFile) {
console.log(result);
}
} else {
// Read from stdin
const inputContent = await readStdin();
if (options.verbose) {
console.error('Reading input from: standard input.');
}
result = await translator.translate(inputContent, translateOptions);
if (outputFile) {
// Check if output file exists and handle erase option
if (!options.erase) {
try {
await fs.access(outputFile);
console.error(chalk.red(`Output file '${outputFile}' already exists. Use -e to overwrite.`));
process.exit(1);
} catch (error) {
// File doesn't exist, continue
}
}
await fs.writeFile(outputFile, result);
if (options.verbose) {
console.error(`Output written to: ${outputFile}`);
}
} else {
console.log(result);
}
}
} catch (error) {
if (error instanceof UTOTException) {
console.error(chalk.red(`Error: ${error.message}`));
process.exit(1);
} else {
console.error(chalk.red(`Unexpected error: ${error.message}`));
if (options.debug) {
console.error(error.stack);
}
process.exit(1);
}
}
}
/**
* Read from stdin
* @returns {Promise<string>} - Input content
*/
function readStdin() {
return new Promise((resolve, reject) => {
let content = '';
process.stdin.setEncoding('utf8');
process.stdin.on('readable', () => {
let chunk;
while (null !== (chunk = process.stdin.read())) {
content += chunk;
}
});
process.stdin.on('end', () => {
resolve(content);
});
process.stdin.on('error', (error) => {
reject(error);
});
});
}
// Handle unhandled promise rejections
process.on('unhandledRejection', (reason, promise) => {
console.error(chalk.red('Unhandled Rejection at:'), promise, chalk.red('reason:'), reason);
process.exit(1);
});
// Handle uncaught exceptions
process.on('uncaughtException', (error) => {
console.error(chalk.red('Uncaught Exception:'), error.message);
if (options && options.debug) {
console.error(error.stack);
}
process.exit(1);
});
// Run main function
main();