diff --git a/src/slang-utils/create-parser.ts b/src/slang-utils/create-parser.ts index 8f511d739..8d90b680e 100644 --- a/src/slang-utils/create-parser.ts +++ b/src/slang-utils/create-parser.ts @@ -21,6 +21,15 @@ function parserAndOutput( }; } +function createError( + { parseOutput }: { parseOutput: ParseOutput }, + reason: string +): Error { + return new Error( + `We encountered the following syntax error:\n\n\t${parseOutput.errors()[0].message}\n\n${reason}` + ); +} + export function createParser( text: string, options: ParserOptions @@ -30,34 +39,41 @@ export function createParser( const result = parserAndOutput(text, compiler); if (!result.parseOutput.isValid()) - throw new Error( - `We encountered the following syntax error:\n\n\t${ - result.parseOutput.errors()[0].message - }\n\nBased on the compiler option provided, we inferred your code to be using Solidity version ${ + throw createError( + result, + `Based on the compiler option provided, we inferred your code to be using Solidity version ${ result.parser.languageVersion }. If you would like to change that, specify a different version in your \`.prettierrc\` file.` ); return result; } + const inferredRanges: string[] = LanguageFacts.inferLanguageVersions(text); const inferredLength = inferredRanges.length; - if (inferredLength === 0) { - throw new Error( - `We couldn't infer a Solidity version base on the pragma statements in your code. If you would like to change that, update the pragmas in your source file, or specify a version in your \`.prettierrc\` file.` + if (inferredLength === 0 || inferredLength === supportedLength) { + const result = parserAndOutput( + text, + supportedVersions[supportedLength - 1] ); + + if (!result.parseOutput.isValid()) + throw createError( + result, + `We couldn't infer a Solidity version based on the pragma statements in your code so we defaulted to ${ + result.parser.languageVersion + }. You might be attempting to use a syntax not yet supported by Slang or you might want to specify a version in your \`.prettierrc\` file.` + ); + return result; } - const result = parserAndOutput( - text, - inferredRanges[inferredLength === supportedLength ? inferredLength - 1 : 0] - ); + + const result = parserAndOutput(text, inferredRanges[0]); if (!result.parseOutput.isValid()) - throw new Error( - `We encountered the following syntax error:\n\n\t${ - result.parseOutput.errors()[0].message - }\n\nBased on the pragma statements, we inferred your code to be using Solidity version ${ + throw createError( + result, + `Based on the pragma statements, we inferred your code to be using Solidity version ${ result.parser.languageVersion }. If you would like to change that, update the pragmas in your source file, or specify a version in your \`.prettierrc\` file.` ); diff --git a/tests/unit/slang-utils/create-parser.test.js b/tests/unit/slang-utils/create-parser.test.js index d8c04cb08..ed318b31e 100644 --- a/tests/unit/slang-utils/create-parser.test.js +++ b/tests/unit/slang-utils/create-parser.test.js @@ -16,14 +16,6 @@ describe('inferLanguage', function () { source: `pragma solidity 0.8.1;`, version: '0.8.1' }, - { - description: 'With nightly commit', - source: `pragma solidity 0.8.18-ci.2023.1.17+commit.e7b959af;`, - version: '0.8.18', - // TODO: unskip this test when addresses this issue - // https://github.com/NomicFoundation/slang/issues/1346 - skip: true - }, { description: 'Caret range and pinned version', source: `pragma solidity ^0.8.0; pragma solidity 0.8.2;`, @@ -84,9 +76,7 @@ describe('inferLanguage', function () { description: 'should use the latest version if the range is outside the supported versions', source: `pragma solidity ^10.0.0;`, - version: latestSupportedVersion, - // TODO: unskip this test when slack fixes the error with ranges outside the supported versions. - skip: true + version: latestSupportedVersion } ]; @@ -120,9 +110,44 @@ describe('inferLanguage', function () { expect(parser.languageVersion).toEqual('0.8.0'); }); - test('should throw an error if there are incompatible ranges', function () { + test('should throw if compiler option does not match the syntax', function () { + expect(() => + createParser(`contract Foo {byte bar;}`, { compiler: '0.8.0' }) + ).toThrow( + 'Based on the compiler option provided, we inferred your code to be using Solidity version' + ); + }); + + test('should throw if pragma is outside the supported version and the syntax does not match with the latest supported version', function () { + expect(() => + createParser(`pragma solidity 10.0.0;contract Foo {byte bar;}`, options) + ).toThrow( + "We couldn't infer a Solidity version based on the pragma statements" + ); + }); + + test('should throw if there is no pragma and the syntax does not match with the latest supported version', function () { + expect(() => createParser(`contract Foo {byte bar;}`, options)).toThrow( + "We couldn't infer a Solidity version based on the pragma statements" + ); + }); + + test('should throw an error if there are incompatible ranges and the syntax does not match with the latest supported version', function () { + expect(() => + createParser( + `pragma solidity ^0.8.0; pragma solidity 0.7.6;contract Foo {byte bar;}`, + options + ) + ).toThrow( + "We couldn't infer a Solidity version based on the pragma statements" + ); + }); + + test('should throw an error if the pragma statement is and the syntax do not match', function () { expect(() => - createParser(`pragma solidity ^0.8.0; pragma solidity 0.7.6;`, options) - ).toThrow(); + createParser(`pragma solidity ^0.8.0;contract Foo {byte bar;}`, options) + ).toThrow( + 'Based on the pragma statements, we inferred your code to be using Solidity version' + ); }); });