Skip to content
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
46 changes: 31 additions & 15 deletions src/slang-utils/create-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<AstNode>
Expand All @@ -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.`
);
Expand Down
53 changes: 39 additions & 14 deletions tests/unit/slang-utils/create-parser.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;`,
Expand Down Expand Up @@ -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
}
];

Expand Down Expand Up @@ -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'
);
});
});