From 6347faa86f111ee2cdce67b6dbc372fb469b3e64 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Tue, 6 Jun 2023 11:18:46 +0200 Subject: [PATCH] Basic infrastructure. --- libsolidity/CMakeLists.txt | 4 + .../analysis/experimental/Analysis.cpp | 26 ++ libsolidity/analysis/experimental/Analysis.h | 43 ++ .../codegen/experimental/IRGenerator.cpp | 160 ++++++++ .../codegen/experimental/IRGenerator.h | 73 ++++ libsolidity/interface/CompilerStack.cpp | 368 +++++++++++------- libsolidity/interface/CompilerStack.h | 12 + 7 files changed, 536 insertions(+), 150 deletions(-) create mode 100644 libsolidity/analysis/experimental/Analysis.cpp create mode 100644 libsolidity/analysis/experimental/Analysis.h create mode 100644 libsolidity/codegen/experimental/IRGenerator.cpp create mode 100644 libsolidity/codegen/experimental/IRGenerator.h diff --git a/libsolidity/CMakeLists.txt b/libsolidity/CMakeLists.txt index 32869ba13..7feb7b294 100644 --- a/libsolidity/CMakeLists.txt +++ b/libsolidity/CMakeLists.txt @@ -46,6 +46,8 @@ set(sources analysis/TypeChecker.h analysis/ViewPureChecker.cpp analysis/ViewPureChecker.h + analysis/experimental/Analysis.cpp + analysis/experimental/Analysis.h ast/AST.cpp ast/AST.h ast/AST_accept.h @@ -90,6 +92,8 @@ set(sources codegen/ReturnInfo.cpp codegen/YulUtilFunctions.h codegen/YulUtilFunctions.cpp + codegen/experimental/IRGenerator.cpp + codegen/experimental/IRGenerator.h codegen/ir/Common.cpp codegen/ir/Common.h codegen/ir/IRGenerator.cpp diff --git a/libsolidity/analysis/experimental/Analysis.cpp b/libsolidity/analysis/experimental/Analysis.cpp new file mode 100644 index 000000000..5138ff280 --- /dev/null +++ b/libsolidity/analysis/experimental/Analysis.cpp @@ -0,0 +1,26 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 +#include + +using namespace solidity::langutil; +using namespace solidity::frontend::experimental; + +bool Analysis::check(ASTNode const&) +{ + return true; +} diff --git a/libsolidity/analysis/experimental/Analysis.h b/libsolidity/analysis/experimental/Analysis.h new file mode 100644 index 000000000..9433508e4 --- /dev/null +++ b/libsolidity/analysis/experimental/Analysis.h @@ -0,0 +1,43 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 +#pragma once + +namespace solidity::frontend +{ +class ASTNode; +} + +namespace solidity::langutil +{ +class ErrorReporter; +} + +namespace solidity::frontend::experimental +{ + +class Analysis +{ +public: + Analysis(langutil::ErrorReporter& _errorReporter): m_errorReporter(_errorReporter) + {} + bool check(ASTNode const& _ast); +private: + langutil::ErrorReporter& m_errorReporter; +}; + +} diff --git a/libsolidity/codegen/experimental/IRGenerator.cpp b/libsolidity/codegen/experimental/IRGenerator.cpp new file mode 100644 index 000000000..0db02a163 --- /dev/null +++ b/libsolidity/codegen/experimental/IRGenerator.cpp @@ -0,0 +1,160 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 + +#include + +#include + +#include +#include +#include +#include + +#include + +#include + +#include + +using namespace std; +using namespace solidity; +using namespace solidity::frontend::experimental; +using namespace solidity::langutil; +using namespace solidity::util; + +string IRGenerator::run( + ContractDefinition const& _contract, + bytes const& /*_cborMetadata*/, + map const& /*_otherYulSources*/ +) const +{ + + Whiskers t(R"( + object "" { + code { + codecopy(0, dataoffset(""), datasize("")) + return(0, datasize("")) + } + object "" { + code { + + } + } + } + )"); + t("CreationObject", IRNames::creationObject(_contract)); + t("DeployedObject", IRNames::deployedObject(_contract)); + t("code", generate(_contract)); + + return t.render(); +} + +string IRGenerator::generate(ContractDefinition const& _contract) const +{ + std::stringstream code; + code << "{\n"; + if (_contract.fallbackFunction()) + { + code << IRNames::function(*_contract.fallbackFunction()) << "()\n"; + } + code << "revert(0,0)\n"; + code << "}\n"; + + for (FunctionDefinition const* f: _contract.definedFunctions()) + code << generate(*f); + + return code.str(); +} + +string IRGenerator::generate(FunctionDefinition const& _function) const +{ + std::stringstream code; + code << "function " << IRNames::function(_function) << "() {\n"; + for (auto _statement: _function.body().statements()) + { + if (auto assembly = dynamic_cast(_statement.get())) + code << generate(*assembly) << "\n"; + else + solUnimplemented("Unsupported statement type."); + } + code << "}\n"; + return code.str(); +} + +namespace { + +struct CopyTranslate: public yul::ASTCopier +{ + CopyTranslate( + yul::Dialect const& _dialect, + map _references + ): m_dialect(_dialect), m_references(std::move(_references)) {} + + using ASTCopier::operator(); + + yul::Expression operator()(yul::Identifier const& _identifier) override + { + // The operator() function is only called in lvalue context. In rvalue context, + // only translate(yul::Identifier) is called. + if (m_references.count(&_identifier)) + return translateReference(_identifier); + else + return ASTCopier::operator()(_identifier); + } + + yul::YulString translateIdentifier(yul::YulString _name) override + { + if (m_dialect.builtin(_name)) + return _name; + else + return yul::YulString{"usr$" + _name.str()}; + } + + yul::Identifier translate(yul::Identifier const& _identifier) override + { + if (!m_references.count(&_identifier)) + return ASTCopier::translate(_identifier); + + yul::Expression translated = translateReference(_identifier); + solAssert(holds_alternative(translated)); + return get(std::move(translated)); + } + +private: + + /// Translates a reference to a local variable, potentially including + /// a suffix. Might return a literal, which causes this to be invalid in + /// lvalue-context. + yul::Expression translateReference(yul::Identifier const&) + { + solUnimplemented("External references in inline assembly not implemented."); + } + + yul::Dialect const& m_dialect; + map m_references; +}; + +} + +string IRGenerator::generate(InlineAssembly const& _assembly) const +{ + CopyTranslate bodyCopier{_assembly.dialect(), {}}; + yul::Statement modified = bodyCopier(_assembly.operations()); + solAssert(holds_alternative(modified)); + return yul::AsmPrinter()(std::get(modified)); +} \ No newline at end of file diff --git a/libsolidity/codegen/experimental/IRGenerator.h b/libsolidity/codegen/experimental/IRGenerator.h new file mode 100644 index 000000000..b2d1a7247 --- /dev/null +++ b/libsolidity/codegen/experimental/IRGenerator.h @@ -0,0 +1,73 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 + +#pragma once + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include + +namespace solidity::frontend::experimental +{ + +class SourceUnit; + +class IRGenerator +{ +public: + IRGenerator( + langutil::EVMVersion _evmVersion, + std::optional _eofVersion, + RevertStrings /*_revertStrings*/, + std::map /*_sourceIndices*/, + langutil::DebugInfoSelection const& _debugInfoSelection, + langutil::CharStreamProvider const* _soliditySourceProvider + ): + m_evmVersion(_evmVersion), + m_eofVersion(_eofVersion), + m_debugInfoSelection(_debugInfoSelection), + m_soliditySourceProvider(_soliditySourceProvider) + {} + + std::string run( + ContractDefinition const& _contract, + bytes const& _cborMetadata, + std::map const& _otherYulSources + ) const; + + std::string generate(ContractDefinition const& _contract) const; + std::string generate(FunctionDefinition const& _function) const; + std::string generate(InlineAssembly const& _assembly) const; +private: + langutil::EVMVersion const m_evmVersion; + std::optional const m_eofVersion; + OptimiserSettings const m_optimiserSettings; + langutil::DebugInfoSelection m_debugInfoSelection = {}; + langutil::CharStreamProvider const* m_soliditySourceProvider = nullptr; +}; + +} diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index f646ff014..9a812ce60 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -56,6 +56,9 @@ #include #include +#include +#include + #include #include @@ -308,6 +311,7 @@ void CompilerStack::reset(bool _keepSettings) { m_stackState = Empty; m_sources.clear(); + m_maxAstId.reset(); m_smtlib2Responses.clear(); m_unhandledSMTLib2Queries.clear(); if (!_keepSettings) @@ -325,6 +329,7 @@ void CompilerStack::reset(bool _keepSettings) m_metadataHash = MetadataHash::IPFS; m_stopAfter = State::CompilationSuccessful; } + m_experimentalAnalysis.reset(); m_globalContext.reset(); m_sourceOrder.clear(); m_contracts.clear(); @@ -407,6 +412,10 @@ bool CompilerStack::parse() m_stackState = (m_stopAfter <= Parsed ? Parsed : ParsedAndImported); storeContractDefinitions(); + + solAssert(!m_maxAstId.has_value()); + m_maxAstId = parser.maxID(); + return true; } @@ -449,6 +458,8 @@ bool CompilerStack::analyze() try { + bool experimentalSolidity = !m_sourceOrder.empty() && m_sourceOrder.front()->ast->experimentalSolidity(); + SyntaxChecker syntaxChecker(m_errorReporter, m_optimiserSettings.runYulOptimiser); for (Source const* source: m_sourceOrder) if (source->ast && !syntaxChecker.checkSyntax(*source->ast)) @@ -456,7 +467,7 @@ bool CompilerStack::analyze() m_globalContext = std::make_shared(); // We need to keep the same resolver during the whole process. - NameAndTypeResolver resolver(*m_globalContext, m_evmVersion, m_errorReporter); + NameAndTypeResolver resolver(*m_globalContext, m_evmVersion, m_errorReporter, experimentalSolidity); for (Source const* source: m_sourceOrder) if (source->ast && !resolver.registerDeclarations(*source->ast)) return false; @@ -470,151 +481,25 @@ bool CompilerStack::analyze() resolver.warnHomonymDeclarations(); - DocStringTagParser docStringTagParser(m_errorReporter); - for (Source const* source: m_sourceOrder) - if (source->ast && !docStringTagParser.parseDocStrings(*source->ast)) - noErrors = false; + { + DocStringTagParser docStringTagParser(m_errorReporter); + for (Source const* source: m_sourceOrder) + if (source->ast && !docStringTagParser.parseDocStrings(*source->ast)) + noErrors = false; + } // Requires DocStringTagParser for (Source const* source: m_sourceOrder) if (source->ast && !resolver.resolveNamesAndTypes(*source->ast)) return false; - DeclarationTypeChecker declarationTypeChecker(m_errorReporter, m_evmVersion); - for (Source const* source: m_sourceOrder) - if (source->ast && !declarationTypeChecker.check(*source->ast)) - return false; - - // Requires DeclarationTypeChecker to have run - for (Source const* source: m_sourceOrder) - if (source->ast && !docStringTagParser.validateDocStringsUsingTypes(*source->ast)) - noErrors = false; - - // Next, we check inheritance, overrides, function collisions and other things at - // contract or function level. - // This also calculates whether a contract is abstract, which is needed by the - // type checker. - ContractLevelChecker contractLevelChecker(m_errorReporter); - - for (Source const* source: m_sourceOrder) - if (auto sourceAst = source->ast) - noErrors = contractLevelChecker.check(*sourceAst); - - // Now we run full type checks that go down to the expression level. This - // cannot be done earlier, because we need cross-contract types and information - // about whether a contract is abstract for the `new` expression. - // This populates the `type` annotation for all expressions. - // - // Note: this does not resolve overloaded functions. In order to do that, types of arguments are needed, - // which is only done one step later. - TypeChecker typeChecker(m_evmVersion, m_errorReporter); - for (Source const* source: m_sourceOrder) - if (source->ast && !typeChecker.checkTypeRequirements(*source->ast)) - noErrors = false; - - if (noErrors) + if (experimentalSolidity) { - // Requires ContractLevelChecker and TypeChecker - DocStringAnalyser docStringAnalyser(m_errorReporter); - for (Source const* source: m_sourceOrder) - if (source->ast && !docStringAnalyser.analyseDocStrings(*source->ast)) - noErrors = false; - } - - if (noErrors) - { - // Checks that can only be done when all types of all AST nodes are known. - PostTypeChecker postTypeChecker(m_errorReporter); - for (Source const* source: m_sourceOrder) - if (source->ast && !postTypeChecker.check(*source->ast)) - noErrors = false; - if (!postTypeChecker.finalize()) + if (!analyzeExperimental()) noErrors = false; } - - // Create & assign callgraphs and check for contract dependency cycles - if (noErrors) - { - createAndAssignCallGraphs(); - annotateInternalFunctionIDs(); - findAndReportCyclicContractDependencies(); - } - - if (noErrors) - for (Source const* source: m_sourceOrder) - if (source->ast && !PostTypeContractLevelChecker{m_errorReporter}.check(*source->ast)) - noErrors = false; - - // Check that immutable variables are never read in c'tors and assigned - // exactly once - if (noErrors) - for (Source const* source: m_sourceOrder) - if (source->ast) - for (ASTPointer const& node: source->ast->nodes()) - if (ContractDefinition* contract = dynamic_cast(node.get())) - ImmutableValidator(m_errorReporter, *contract).analyze(); - - if (noErrors) - { - // Control flow graph generator and analyzer. It can check for issues such as - // variable is used before it is assigned to. - CFG cfg(m_errorReporter); - for (Source const* source: m_sourceOrder) - if (source->ast && !cfg.constructFlow(*source->ast)) - noErrors = false; - - if (noErrors) - { - ControlFlowRevertPruner pruner(cfg); - pruner.run(); - - ControlFlowAnalyzer controlFlowAnalyzer(cfg, m_errorReporter); - if (!controlFlowAnalyzer.run()) - noErrors = false; - } - } - - if (noErrors) - { - // Checks for common mistakes. Only generates warnings. - StaticAnalyzer staticAnalyzer(m_errorReporter); - for (Source const* source: m_sourceOrder) - if (source->ast && !staticAnalyzer.analyze(*source->ast)) - noErrors = false; - } - - if (noErrors) - { - // Check for state mutability in every function. - std::vector> ast; - for (Source const* source: m_sourceOrder) - if (source->ast) - ast.push_back(source->ast); - - if (!ViewPureChecker(ast, m_errorReporter).check()) - noErrors = false; - } - - if (noErrors) - { - // Run SMTChecker - - auto allSources = util::applyMap(m_sourceOrder, [](Source const* _source) { return _source->ast; }); - if (ModelChecker::isPragmaPresent(allSources)) - m_modelCheckerSettings.engine = ModelCheckerEngine::All(); - - // m_modelCheckerSettings is spread to engines and solver interfaces, - // so we need to check whether the enabled ones are available before building the classes. - if (m_modelCheckerSettings.engine.any()) - m_modelCheckerSettings.solvers = ModelChecker::checkRequestedSolvers(m_modelCheckerSettings.solvers, m_errorReporter); - - ModelChecker modelChecker(m_errorReporter, *this, m_smtlib2Responses, m_modelCheckerSettings, m_readFile); - modelChecker.checkRequestedSourcesAndContracts(allSources); - for (Source const* source: m_sourceOrder) - if (source->ast) - modelChecker.analyze(*source->ast); - m_unhandledSMTLib2Queries += modelChecker.unhandledQueries(); - } + else if (!analyzeLegacy(noErrors)) + noErrors = false; } catch (FatalError const&) { @@ -630,6 +515,165 @@ bool CompilerStack::analyze() return true; } + +bool CompilerStack::analyzeLegacy(bool _noErrorsSoFar) +{ + bool noErrors = _noErrorsSoFar; + + DeclarationTypeChecker declarationTypeChecker(m_errorReporter, m_evmVersion); + for (Source const* source: m_sourceOrder) + if (source->ast && !declarationTypeChecker.check(*source->ast)) + return false; + + // Requires DeclarationTypeChecker to have run + DocStringTagParser docStringTagParser(m_errorReporter); + for (Source const* source: m_sourceOrder) + if (source->ast && !docStringTagParser.validateDocStringsUsingTypes(*source->ast)) + noErrors = false; + + // Next, we check inheritance, overrides, function collisions and other things at + // contract or function level. + // This also calculates whether a contract is abstract, which is needed by the + // type checker. + ContractLevelChecker contractLevelChecker(m_errorReporter); + + for (Source const* source: m_sourceOrder) + if (auto sourceAst = source->ast) + noErrors = contractLevelChecker.check(*sourceAst); + + // Now we run full type checks that go down to the expression level. This + // cannot be done earlier, because we need cross-contract types and information + // about whether a contract is abstract for the `new` expression. + // This populates the `type` annotation for all expressions. + // + // Note: this does not resolve overloaded functions. In order to do that, types of arguments are needed, + // which is only done one step later. + TypeChecker typeChecker(m_evmVersion, m_errorReporter); + for (Source const* source: m_sourceOrder) + if (source->ast && !typeChecker.checkTypeRequirements(*source->ast)) + noErrors = false; + + if (noErrors) + { + // Requires ContractLevelChecker and TypeChecker + DocStringAnalyser docStringAnalyser(m_errorReporter); + for (Source const* source: m_sourceOrder) + if (source->ast && !docStringAnalyser.analyseDocStrings(*source->ast)) + noErrors = false; + } + + if (noErrors) + { + // Checks that can only be done when all types of all AST nodes are known. + PostTypeChecker postTypeChecker(m_errorReporter); + for (Source const* source: m_sourceOrder) + if (source->ast && !postTypeChecker.check(*source->ast)) + noErrors = false; + if (!postTypeChecker.finalize()) + noErrors = false; + } + + // Create & assign callgraphs and check for contract dependency cycles + if (noErrors) + { + createAndAssignCallGraphs(); + annotateInternalFunctionIDs(); + findAndReportCyclicContractDependencies(); + } + + if (noErrors) + for (Source const* source: m_sourceOrder) + if (source->ast && !PostTypeContractLevelChecker{m_errorReporter}.check(*source->ast)) + noErrors = false; + + // Check that immutable variables are never read in c'tors and assigned + // exactly once + if (noErrors) + for (Source const* source: m_sourceOrder) + if (source->ast) + for (ASTPointer const& node: source->ast->nodes()) + if (ContractDefinition* contract = dynamic_cast(node.get())) + ImmutableValidator(m_errorReporter, *contract).analyze(); + + if (noErrors) + { + // Control flow graph generator and analyzer. It can check for issues such as + // variable is used before it is assigned to. + CFG cfg(m_errorReporter); + for (Source const* source: m_sourceOrder) + if (source->ast && !cfg.constructFlow(*source->ast)) + noErrors = false; + + if (noErrors) + { + ControlFlowRevertPruner pruner(cfg); + pruner.run(); + + ControlFlowAnalyzer controlFlowAnalyzer(cfg, m_errorReporter); + if (!controlFlowAnalyzer.run()) + noErrors = false; + } + } + + if (noErrors) + { + // Checks for common mistakes. Only generates warnings. + StaticAnalyzer staticAnalyzer(m_errorReporter); + for (Source const* source: m_sourceOrder) + if (source->ast && !staticAnalyzer.analyze(*source->ast)) + noErrors = false; + } + + if (noErrors) + { + // Check for state mutability in every function. + std::vector> ast; + for (Source const* source: m_sourceOrder) + if (source->ast) + ast.push_back(source->ast); + + if (!ViewPureChecker(ast, m_errorReporter).check()) + noErrors = false; + } + + if (noErrors) + { + // Run SMTChecker + + auto allSources = util::applyMap(m_sourceOrder, [](Source const* _source) { return _source->ast; }); + if (ModelChecker::isPragmaPresent(allSources)) + m_modelCheckerSettings.engine = ModelCheckerEngine::All(); + + // m_modelCheckerSettings is spread to engines and solver interfaces, + // so we need to check whether the enabled ones are available before building the classes. + if (m_modelCheckerSettings.engine.any()) + m_modelCheckerSettings.solvers = ModelChecker::checkRequestedSolvers(m_modelCheckerSettings.solvers, m_errorReporter); + + ModelChecker modelChecker(m_errorReporter, *this, m_smtlib2Responses, m_modelCheckerSettings, m_readFile); + modelChecker.checkRequestedSourcesAndContracts(allSources); + for (Source const* source: m_sourceOrder) + if (source->ast) + modelChecker.analyze(*source->ast); + m_unhandledSMTLib2Queries += modelChecker.unhandledQueries(); + } + + return noErrors; +} + +bool CompilerStack::analyzeExperimental() +{ + bool noErrors = true; + solAssert(m_maxAstId && *m_maxAstId >= 0); + m_experimentalAnalysis = std::make_unique(m_errorReporter, static_cast(*m_maxAstId)); + std::vector> sourceAsts; + for (Source const* source: m_sourceOrder) + if (source->ast) + sourceAsts.emplace_back(source->ast); + if (!m_experimentalAnalysis->check(sourceAsts)) + noErrors = false; + return noErrors; +} + bool CompilerStack::parseAndAnalyze(State _stopAfter) { m_stopAfter = _stopAfter; @@ -694,7 +738,11 @@ bool CompilerStack::compile(State _stopAfter) if (m_viaIR) generateEVMFromIR(*contract); else + { + if (m_experimentalAnalysis) + solThrow(CompilerError, "Legacy codegen after experimental analysis is unsupported."); compileContract(*contract, otherCompilers); + } } } catch (Error const& _error) @@ -1452,19 +1500,39 @@ void CompilerStack::generateIR(ContractDefinition const& _contract) for (auto const& pair: m_contracts) otherYulSources.emplace(pair.second.contract, pair.second.yulIR); - IRGenerator generator( - m_evmVersion, - m_eofVersion, - m_revertStrings, - sourceIndices(), - m_debugInfoSelection, - this - ); - compiledContract.yulIR = generator.run( - _contract, - createCBORMetadata(compiledContract, /* _forIR */ true), - otherYulSources - ); + if (m_experimentalAnalysis) + { + experimental::IRGenerator generator( + m_evmVersion, + m_eofVersion, + m_revertStrings, + sourceIndices(), + m_debugInfoSelection, + this, + *m_experimentalAnalysis + ); + compiledContract.yulIR = generator.run( + _contract, + {}, // TODO: createCBORMetadata(compiledContract, /* _forIR */ true), + otherYulSources + ); + } + else + { + IRGenerator generator( + m_evmVersion, + m_eofVersion, + m_revertStrings, + sourceIndices(), + m_debugInfoSelection, + this + ); + compiledContract.yulIR = generator.run( + _contract, + createCBORMetadata(compiledContract, /* _forIR */ true), + otherYulSources + ); + } yul::YulStack stack( m_evmVersion, diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h index 0227896ae..84ff5bdbe 100644 --- a/libsolidity/interface/CompilerStack.h +++ b/libsolidity/interface/CompilerStack.h @@ -81,6 +81,10 @@ class Compiler; class GlobalContext; class Natspec; class DeclarationContainer; +namespace experimental +{ +class Analysis; +} /** * Easy to use and self-contained Solidity compiler with as few header dependencies as possible. @@ -221,6 +225,13 @@ public: /// @returns false on error. bool analyze(); + /// Perform the analysis steps of legacy language mode. + /// @returns false on error. + bool analyzeLegacy(bool _noErrorsSoFar); + /// Perform the analysis steps of experimental language mode. + /// @returns false on error. + bool analyzeExperimental(); + /// Parses and analyzes all source units that were added /// @returns false on error. bool parseAndAnalyze(State _stopAfter = State::CompilationSuccessful); @@ -500,6 +511,7 @@ private: langutil::ErrorList m_errorList; langutil::ErrorReporter m_errorReporter; + std::unique_ptr m_experimentalAnalysis; bool m_metadataLiteralSources = false; MetadataHash m_metadataHash = MetadataHash::IPFS; langutil::DebugInfoSelection m_debugInfoSelection = langutil::DebugInfoSelection::Default();