Skip to content

Try loading a spec/cfg with the MC prefix before loading the #233

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 21, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,7 @@
"dependencies": {
"await-notify": "^1.0.1",
"moment": "^2.24.0",
"vscode-uri": "^3.0.2",
"vscode-debugadapter": "^1.42.1"
}
}
59 changes: 51 additions & 8 deletions src/commands/checkModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { saveStreamToFile } from '../outputSaver';
import { replaceExtension, LANG_TLAPLUS, LANG_TLAPLUS_CFG, listFiles, exists } from '../common';
import { ModelCheckResultSource, ModelCheckResult, SpecFiles } from '../model/check';
import { ToolOutputChannel } from '../outputChannels';
import { Utils } from 'vscode-uri';

export const CMD_CHECK_MODEL_RUN = 'tlaplus.model.check.run';
export const CMD_CHECK_MODEL_RUN_AGAIN = 'tlaplus.model.check.runAgain';
Expand Down Expand Up @@ -44,7 +45,8 @@ export async function checkModel(
if (!uri) {
return;
}
const specFiles = await getSpecFiles(uri);

const specFiles = await getSpecFiles(uri, false);
if (!specFiles) {
return;
}
Expand Down Expand Up @@ -218,32 +220,73 @@ function attachFileSaver(tlaFilePath: string, proc: ChildProcess) {
/**
* Finds all files that needed to run model check.
*/
export async function getSpecFiles(fileUri: vscode.Uri): Promise<SpecFiles | undefined> {
export async function getSpecFiles(fileUri: vscode.Uri, warn = true): Promise<SpecFiles | undefined> {
let specFiles;

// a) Check the given input if it exists.
specFiles = await checkSpecFiles(fileUri, false);
if (specFiles) {
return specFiles;
}
// b) Check alternatives:
// Unless the given filePath already starts with 'MC', prepend MC to the name
// and check if it exists. If yes, it becomes the spec file. If not, fall back
// to the original file. The assumptions is that a user usually has Spec.tla
// open in the editor and doesn't want to switch to MC.tla before model-checking.
// TODO: Ideally, we wouldn't just check filenames here but check the parse result
// TODO: if the module in MCSpec.tla actually extends the module in Spec.
const b = Utils.basename(fileUri);
if (!b.startsWith('MC') && !b.endsWith('.cfg')) {
const str = fileUri.toString();
const n = str.substr(0, str.lastIndexOf(b)) + 'MC' + b;
const filePath = vscode.Uri.parse(n).fsPath;
specFiles = new SpecFiles(filePath, replaceExtension(filePath, 'cfg'));
// Here, we make sure that the .cfg *and* the .tla exist.
let canRun = true;
canRun = await checkModelExists(specFiles.cfgFilePath, warn);
canRun = canRun && await checkModuleExists(specFiles.tlaFilePath, warn);
if (canRun) {
return specFiles;
}
}
// c) Deliberately trigger the warning dialog by checking the given input again
// knowing that it doesn't exist.
return await checkSpecFiles(fileUri, true);
}

async function checkSpecAndConfigFiles(specFiles: SpecFiles, warn = true): Promise<SpecFiles | undefined> {
let canRun = true;
canRun = await checkModelExists(specFiles.cfgFilePath, warn);
canRun = canRun && await checkModuleExists(specFiles.tlaFilePath, warn);
return canRun ? specFiles : undefined;
}

async function checkSpecFiles(fileUri: vscode.Uri, warn = true): Promise<SpecFiles | undefined> {
const filePath = fileUri.fsPath;
let specFiles;
let canRun = true;
if (filePath.endsWith('.cfg')) {
specFiles = new SpecFiles(replaceExtension(filePath, 'tla'), filePath);
canRun = await checkModuleExists(specFiles.tlaFilePath);
canRun = await checkModuleExists(specFiles.tlaFilePath, warn);
} else if (filePath.endsWith('.tla')) {
specFiles = new SpecFiles(filePath, replaceExtension(filePath, 'cfg'));
canRun = await checkModelExists(specFiles.cfgFilePath);
canRun = await checkModelExists(specFiles.cfgFilePath, warn);
}
return canRun ? specFiles : undefined;
}

async function checkModuleExists(modulePath: string): Promise<boolean> {
async function checkModuleExists(modulePath: string, warn = true): Promise<boolean> {
const moduleExists = await exists(modulePath);
if (!moduleExists) {
if (!moduleExists && warn) {
const moduleFile = path.basename(modulePath);
vscode.window.showWarningMessage(`Corresponding TLA+ module file ${moduleFile} doesn't exist.`);
}
return moduleExists;
}

async function checkModelExists(cfgPath: string): Promise<boolean> {
async function checkModelExists(cfgPath: string, warn = true): Promise<boolean> {
const cfgExists = await exists(cfgPath);
if (!cfgExists) {
if (!cfgExists && warn) {
showConfigAbsenceWarning(cfgPath);
}
return cfgExists;
Expand Down