From cc49d87e3e0a56f2bc04db454a2180211e2c1eca Mon Sep 17 00:00:00 2001 From: Klaus Date: Wed, 11 Dec 2024 12:03:38 +1300 Subject: [PATCH] caching the parser for multiple calls to the parser --- src/slang-utils/create-parser.ts | 15 ++++++-- tests/unit/slang-utils/create-parser.test.js | 39 ++++++++++++++------ 2 files changed, 39 insertions(+), 15 deletions(-) diff --git a/src/slang-utils/create-parser.ts b/src/slang-utils/create-parser.ts index 99946b16..aa0eb2d5 100644 --- a/src/slang-utils/create-parser.ts +++ b/src/slang-utils/create-parser.ts @@ -34,18 +34,21 @@ const query = Query.parse( '[VersionPragma @versionRanges [VersionExpressionSets]]' ); +let parser: Parser; + export function createParser( text: string, options: ParserOptions ): [Parser, ParseOutput] { const compiler = maxSatisfying(supportedVersions, options.compiler); - let parser: Parser; if (compiler) { - parser = Parser.create(compiler); + if (parser?.version !== compiler) { + parser = Parser.create(compiler); + } return [parser, parser.parse(NonterminalKind.SourceUnit, text)]; } - parser = Parser.create(milestoneVersions[0]); + parser = parser ?? Parser.create(milestoneVersions[0]); let parseOutput; let inferredRanges: string[] = []; @@ -53,7 +56,11 @@ export function createParser( parseOutput = parser.parse(NonterminalKind.SourceUnit, text); inferredRanges = tryToCollectPragmas(parseOutput, parser); } catch { - for (let i = 1; i <= milestoneVersions.length; i += 1) { + for ( + let i = parser.version === milestoneVersions[0] ? 1 : 0; + i <= milestoneVersions.length; + i += 1 + ) { try { const version = milestoneVersions[i]; parser = Parser.create(version); diff --git a/tests/unit/slang-utils/create-parser.test.js b/tests/unit/slang-utils/create-parser.test.js index 6bacab62..4fabe59a 100644 --- a/tests/unit/slang-utils/create-parser.test.js +++ b/tests/unit/slang-utils/create-parser.test.js @@ -70,17 +70,6 @@ describe('inferLanguage', function () { 0.8.2;`, version: '0.8.2' }, - { - description: 'should use the latest version if the source has no pragmas', - source: `contract Foo {}`, - version: latestSupportedVersion - }, - { - description: - 'should use the latest valid version if the source has no pragmas and the syntax is old', - source: `contract Foo {byte bar;}`, - version: '0.7.6' - }, { description: 'should use the latest version if the range is outside the supported versions', @@ -96,6 +85,34 @@ describe('inferLanguage', function () { }); } + test('should use the cached or the latest successful version if the source has no pragmas', function () { + createParser(`pragma solidity 0.8.28;`, options); + let [parser] = createParser(`contract Foo {}`, options); + expect(parser.version).toEqual('0.8.28'); + + createParser(`pragma solidity 0.8.2;`, options); + [parser] = createParser(`contract Foo {}`, options); + expect(parser.version).toEqual('0.8.2'); + + [parser] = createParser(`contract Foo {byte bar;}`, options); + expect(parser.version).toEqual('0.7.6'); + }); + + test('should use compiler option if given', function () { + let [parser] = createParser(`pragma solidity ^0.8.0;`, { + compiler: '0.8.20' + }); + expect(parser.version).toEqual('0.8.20'); + + [parser] = createParser(`pragma solidity ^0.8.0;`, { + compiler: '0.8.2' + }); + expect(parser.version).toEqual('0.8.2'); + + [parser] = createParser(`pragma solidity ^0.8.0;`, {}); + expect(parser.version).toEqual(latestSupportedVersion); + }); + test('should throw when a pragma is broken by new lines, whitespace and comments', function () { expect(() => createParser(