Stop after parsing.

This commit is contained in:
chriseth
2020-09-30 16:57:49 +02:00
committed by Mathias Baumann
parent 4c02cd2310
commit fda8bde2d7
70 changed files with 5440 additions and 105 deletions
+34 -20
View File
@@ -23,6 +23,7 @@
#include <libsolidity/ast/ASTJsonConverter.h>
#include <libsolidity/ast/AST.h>
#include <libsolidity/ast/TypeProvider.h>
#include <libyul/AsmJsonConverter.h>
#include <libyul/AsmData.h>
@@ -69,8 +70,9 @@ void addIfSet(std::vector<pair<string, Json::Value>>& _attributes, string const&
namespace solidity::frontend
{
ASTJsonConverter::ASTJsonConverter(bool _legacy, map<string, unsigned> _sourceIndices):
ASTJsonConverter::ASTJsonConverter(bool _legacy, CompilerStack::State _stackState, map<string, unsigned> _sourceIndices):
m_legacy(_legacy),
m_stackState(_stackState),
m_sourceIndices(std::move(_sourceIndices))
{
}
@@ -204,7 +206,6 @@ void ASTJsonConverter::appendExpressionAttributes(
{
std::vector<pair<string, Json::Value>> exprAttributes = {
make_pair("typeDescriptions", typePointerToJson(_annotation.type)),
make_pair("lValueRequested", _annotation.willBeWrittenTo),
make_pair("argumentTypes", typePointerToJson(_annotation.arguments))
};
@@ -212,6 +213,9 @@ void ASTJsonConverter::appendExpressionAttributes(
addIfSet(exprAttributes, "isPure", _annotation.isPure);
addIfSet(exprAttributes, "isConstant", _annotation.isConstant);
if (m_stackState > CompilerStack::State::ParsedAndImported)
exprAttributes.emplace_back("lValueRequested", _annotation.willBeWrittenTo);
_attributes += exprAttributes;
}
@@ -260,6 +264,7 @@ bool ASTJsonConverter::visit(SourceUnit const& _node)
addIfSet(attributes, "absolutePath", _node.annotation().path);
setJsonNode(_node, "SourceUnit", std::move(attributes));
return false;
}
@@ -268,7 +273,7 @@ bool ASTJsonConverter::visit(PragmaDirective const& _node)
Json::Value literals(Json::arrayValue);
for (auto const& literal: _node.literals())
literals.append(literal);
setJsonNode( _node, "PragmaDirective", {
setJsonNode(_node, "PragmaDirective", {
make_pair("literals", std::move(literals))
});
return false;
@@ -278,7 +283,7 @@ bool ASTJsonConverter::visit(ImportDirective const& _node)
{
std::vector<pair<string, Json::Value>> attributes = {
make_pair("file", _node.path()),
make_pair(m_legacy ? "SourceUnit" : "sourceUnit", nodeId(*_node.annotation().sourceUnit)),
make_pair(m_legacy ? "SourceUnit" : "sourceUnit", idOrNull(_node.annotation().sourceUnit)),
make_pair("scope", idOrNull(_node.scope()))
};
@@ -395,18 +400,11 @@ bool ASTJsonConverter::visit(OverrideSpecifier const& _node)
bool ASTJsonConverter::visit(FunctionDefinition const& _node)
{
Visibility visibility;
if (_node.isConstructor())
visibility = _node.annotation().contract->abstract() ? Visibility::Internal : Visibility::Public;
else
visibility = _node.visibility();
std::vector<pair<string, Json::Value>> attributes = {
make_pair("name", _node.name()),
make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json::nullValue),
make_pair("kind", _node.isFree() ? "freeFunction" : TokenTraits::toString(_node.kind())),
make_pair("stateMutability", stateMutabilityToString(_node.stateMutability())),
make_pair("visibility", Declaration::visibilityToString(visibility)),
make_pair("virtual", _node.markedVirtual()),
make_pair("overrides", _node.overrides() ? toJson(*_node.overrides()) : Json::nullValue),
make_pair("parameters", toJson(_node.parameterList())),
@@ -417,7 +415,19 @@ bool ASTJsonConverter::visit(FunctionDefinition const& _node)
make_pair("scope", idOrNull(_node.scope()))
};
if (_node.isPartOfExternalInterface())
optional<Visibility> visibility;
if (_node.isConstructor())
{
if (_node.annotation().contract)
visibility = _node.annotation().contract->abstract() ? Visibility::Internal : Visibility::Public;
}
else
visibility = _node.visibility();
if (visibility)
attributes.emplace_back("visibility", Declaration::visibilityToString(*visibility));
if (_node.isPartOfExternalInterface() && m_stackState > CompilerStack::State::ParsedAndImported)
attributes.emplace_back("functionSelector", _node.externalIdentifierHex());
if (!_node.annotation().baseFunctions.empty())
attributes.emplace_back(make_pair("baseFunctions", getContainerIds(_node.annotation().baseFunctions, true)));
@@ -718,7 +728,7 @@ bool ASTJsonConverter::visit(Assignment const& _node)
make_pair("rightHandSide", toJson(_node.rightHandSide()))
};
appendExpressionAttributes(attributes, _node.annotation());
setJsonNode( _node, "Assignment", std::move(attributes));
setJsonNode(_node, "Assignment", std::move(attributes));
return false;
}
@@ -770,15 +780,19 @@ bool ASTJsonConverter::visit(FunctionCall const& _node)
make_pair("tryCall", _node.annotation().tryCall)
};
FunctionCallKind nodeKind = *_node.annotation().kind;
if (m_legacy)
if (_node.annotation().kind.set())
{
attributes.emplace_back("isStructConstructorCall", nodeKind == FunctionCallKind::StructConstructorCall);
attributes.emplace_back("type_conversion", nodeKind == FunctionCallKind::TypeConversion);
FunctionCallKind nodeKind = *_node.annotation().kind;
if (m_legacy)
{
attributes.emplace_back("isStructConstructorCall", nodeKind == FunctionCallKind::StructConstructorCall);
attributes.emplace_back("type_conversion", nodeKind == FunctionCallKind::TypeConversion);
}
else
attributes.emplace_back("kind", functionCallKind(nodeKind));
}
else
attributes.emplace_back("kind", functionCallKind(nodeKind));
appendExpressionAttributes(attributes, _node.annotation());
setJsonNode(_node, "FunctionCall", std::move(attributes));
return false;
+4
View File
@@ -25,6 +25,7 @@
#include <libsolidity/ast/ASTAnnotations.h>
#include <libsolidity/ast/ASTVisitor.h>
#include <libsolidity/interface/CompilerStack.h>
#include <liblangutil/Exceptions.h>
#include <json/json.h>
@@ -51,9 +52,11 @@ class ASTJsonConverter: public ASTConstVisitor
public:
/// Create a converter to JSON for the given abstract syntax tree.
/// @a _legacy if true, use legacy format
/// @a _stackState state of the compiler stack to avoid outputting incomplete data
/// @a _sourceIndices is used to abbreviate source names in source locations.
explicit ASTJsonConverter(
bool _legacy,
CompilerStack::State _stackState,
std::map<std::string, unsigned> _sourceIndices = std::map<std::string, unsigned>()
);
/// Output the json representation of the AST to _stream.
@@ -189,6 +192,7 @@ private:
}
bool m_legacy = false; ///< if true, use legacy format
CompilerStack::State m_stackState = CompilerStack::State::Empty; ///< Used to only access information that already exists
bool m_inEvent = false; ///< whether we are currently inside an event or not
Json::Value m_currentValue;
std::map<std::string, unsigned> m_sourceIndices;
+3 -1
View File
@@ -140,7 +140,9 @@ util::Result<TypePointers> transformParametersToExternal(TypePointers const& _pa
for (auto const& type: _parameters)
{
if (TypePointer ext = type->interfaceType(_inLibrary).get())
if (!type)
return util::Result<TypePointers>::err("Type information not present.");
else if (TypePointer ext = type->interfaceType(_inLibrary).get())
transformed.push_back(ext);
else
return util::Result<TypePointers>::err("Parameter should have external type.");
+69 -47
View File
@@ -124,7 +124,7 @@ std::optional<CompilerStack::Remapping> CompilerStack::parseRemapping(string con
void CompilerStack::setRemappings(vector<Remapping> const& _remappings)
{
if (m_stackState >= ParsingPerformed)
if (m_stackState >= ParsedAndImported)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Must set remappings before parsing."));
for (auto const& remapping: _remappings)
solAssert(!remapping.prefix.empty(), "");
@@ -133,21 +133,21 @@ void CompilerStack::setRemappings(vector<Remapping> const& _remappings)
void CompilerStack::setEVMVersion(langutil::EVMVersion _version)
{
if (m_stackState >= ParsingPerformed)
if (m_stackState >= ParsedAndImported)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Must set EVM version before parsing."));
m_evmVersion = _version;
}
void CompilerStack::setSMTSolverChoice(smtutil::SMTSolverChoice _enabledSMTSolvers)
{
if (m_stackState >= ParsingPerformed)
if (m_stackState >= ParsedAndImported)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Must set enabled SMT solvers before parsing."));
m_enabledSMTSolvers = _enabledSMTSolvers;
}
void CompilerStack::setLibraries(std::map<std::string, util::h160> const& _libraries)
{
if (m_stackState >= ParsingPerformed)
if (m_stackState >= ParsedAndImported)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Must set libraries before parsing."));
m_libraries = _libraries;
}
@@ -161,14 +161,14 @@ void CompilerStack::setOptimiserSettings(bool _optimize, unsigned _runs)
void CompilerStack::setOptimiserSettings(OptimiserSettings _settings)
{
if (m_stackState >= ParsingPerformed)
if (m_stackState >= ParsedAndImported)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Must set optimiser settings before parsing."));
m_optimiserSettings = std::move(_settings);
}
void CompilerStack::setRevertStringBehaviour(RevertStrings _revertStrings)
{
if (m_stackState >= ParsingPerformed)
if (m_stackState >= ParsedAndImported)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Must set revert string settings before parsing."));
solUnimplementedAssert(_revertStrings != RevertStrings::VerboseDebug, "");
m_revertStrings = _revertStrings;
@@ -176,21 +176,21 @@ void CompilerStack::setRevertStringBehaviour(RevertStrings _revertStrings)
void CompilerStack::useMetadataLiteralSources(bool _metadataLiteralSources)
{
if (m_stackState >= ParsingPerformed)
if (m_stackState >= ParsedAndImported)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Must set use literal sources before parsing."));
m_metadataLiteralSources = _metadataLiteralSources;
}
void CompilerStack::setMetadataHash(MetadataHash _metadataHash)
{
if (m_stackState >= ParsingPerformed)
if (m_stackState >= ParsedAndImported)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Must set metadata hash before parsing."));
m_metadataHash = _metadataHash;
}
void CompilerStack::addSMTLib2Response(h256 const& _hash, string const& _response)
{
if (m_stackState >= ParsingPerformed)
if (m_stackState >= ParsedAndImported)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Must add SMTLib2 responses before parsing."));
m_smtlib2Responses[_hash] = _response;
}
@@ -214,6 +214,7 @@ void CompilerStack::reset(bool _keepSettings)
m_optimiserSettings = OptimiserSettings::minimal();
m_metadataLiteralSources = false;
m_metadataHash = MetadataHash::IPFS;
m_stopAfter = State::CompilationSuccessful;
}
m_globalContext.reset();
m_sourceOrder.clear();
@@ -247,6 +248,7 @@ bool CompilerStack::parse()
vector<string> sourcesToParse;
for (auto const& s: m_sources)
sourcesToParse.push_back(s.first);
for (size_t i = 0; i < sourcesToParse.size(); ++i)
{
string const& path = sourcesToParse[i];
@@ -258,19 +260,26 @@ bool CompilerStack::parse()
else
{
source.ast->annotation().path = path;
for (auto const& newSource: loadMissingSources(*source.ast, path))
{
string const& newPath = newSource.first;
string const& newContents = newSource.second;
m_sources[newPath].scanner = make_shared<Scanner>(CharStream(newContents, newPath));
sourcesToParse.push_back(newPath);
}
if (m_stopAfter >= ParsedAndImported)
for (auto const& newSource: loadMissingSources(*source.ast, path))
{
string const& newPath = newSource.first;
string const& newContents = newSource.second;
m_sources[newPath].scanner = make_shared<Scanner>(CharStream(newContents, newPath));
sourcesToParse.push_back(newPath);
}
}
}
m_stackState = ParsingPerformed;
if (m_stopAfter <= Parsed)
m_stackState = Parsed;
else
m_stackState = ParsedAndImported;
if (!Error::containsOnlyWarnings(m_errorReporter.errors()))
m_hasError = true;
storeContractDefinitions();
return !m_hasError;
}
@@ -290,13 +299,15 @@ void CompilerStack::importASTs(map<string, Json::Value> const& _sources)
source.scanner = scanner;
m_sources[path] = source;
}
m_stackState = ParsingPerformed;
m_stackState = ParsedAndImported;
m_importedSources = true;
storeContractDefinitions();
}
bool CompilerStack::analyze()
{
if (m_stackState != ParsingPerformed || m_stackState >= AnalysisPerformed)
if (m_stackState != ParsedAndImported || m_stackState >= AnalysisPerformed)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Must call analyze only after parsing was performed."));
resolveImports();
@@ -336,26 +347,6 @@ bool CompilerStack::analyze()
if (source->ast && !resolver.resolveNamesAndTypes(*source->ast))
return false;
// Store contract definitions.
for (Source const* source: m_sourceOrder)
if (source->ast)
for (
ContractDefinition const* contract:
ASTNode::filteredNodes<ContractDefinition>(source->ast->nodes())
)
{
// Note that we now reference contracts by their fully qualified names, and
// thus contracts can only conflict if declared in the same source file. This
// should already cause a double-declaration error elsewhere.
if (!m_contracts.count(contract->fullyQualifiedName()))
m_contracts[contract->fullyQualifiedName()].contract = contract;
else
solAssert(
m_errorReporter.hasErrors(),
"Contract already present (name clash?), but no error was reported."
);
}
DeclarationTypeChecker declarationTypeChecker(m_errorReporter, m_evmVersion);
for (Source const* source: m_sourceOrder)
if (source->ast && !declarationTypeChecker.check(*source->ast))
@@ -469,9 +460,13 @@ bool CompilerStack::analyze()
return !m_hasError;
}
bool CompilerStack::parseAndAnalyze()
bool CompilerStack::parseAndAnalyze(State _stopAfter)
{
m_stopAfter = _stopAfter;
bool success = parse();
if (m_stackState >= m_stopAfter)
return success;
if (success || m_parserErrorRecovery)
success = analyze();
return success;
@@ -502,12 +497,16 @@ bool CompilerStack::isRequestedContract(ContractDefinition const& _contract) con
return false;
}
bool CompilerStack::compile()
bool CompilerStack::compile(State _stopAfter)
{
m_stopAfter = _stopAfter;
if (m_stackState < AnalysisPerformed)
if (!parseAndAnalyze())
if (!parseAndAnalyze(_stopAfter))
return false;
if (m_stackState >= m_stopAfter)
return true;
if (m_hasError)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Called compile with errors."));
@@ -574,7 +573,7 @@ void CompilerStack::link()
vector<string> CompilerStack::contractNames() const
{
if (m_stackState < AnalysisPerformed)
if (m_stackState < Parsed)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
vector<string> contractNames;
for (auto const& contract: m_contracts)
@@ -921,7 +920,7 @@ Scanner const& CompilerStack::scanner(string const& _sourceName) const
SourceUnit const& CompilerStack::ast(string const& _sourceName) const
{
if (m_stackState < ParsingPerformed)
if (m_stackState < Parsed)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing not yet performed."));
if (!source(_sourceName).ast && !m_parserErrorRecovery)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
@@ -994,7 +993,7 @@ string const& CompilerStack::Source::ipfsUrl() const
StringMap CompilerStack::loadMissingSources(SourceUnit const& _ast, std::string const& _sourcePath)
{
solAssert(m_stackState < ParsingPerformed, "");
solAssert(m_stackState < ParsedAndImported, "");
StringMap newSources;
try
{
@@ -1038,7 +1037,7 @@ StringMap CompilerStack::loadMissingSources(SourceUnit const& _ast, std::string
string CompilerStack::applyRemapping(string const& _path, string const& _context)
{
solAssert(m_stackState < ParsingPerformed, "");
solAssert(m_stackState < ParsedAndImported, "");
// Try to find the longest prefix match in all remappings that are active in the current context.
auto isPrefixOf = [](string const& _a, string const& _b)
{
@@ -1080,7 +1079,7 @@ string CompilerStack::applyRemapping(string const& _path, string const& _context
void CompilerStack::resolveImports()
{
solAssert(m_stackState == ParsingPerformed, "");
solAssert(m_stackState == ParsedAndImported, "");
// topological sorting (depth first search) of the import graph, cutting potential cycles
vector<Source const*> sourceOrder;
@@ -1110,6 +1109,29 @@ void CompilerStack::resolveImports()
swap(m_sourceOrder, sourceOrder);
}
void CompilerStack::storeContractDefinitions()
{
for (auto const& pair: m_sources)
if (pair.second.ast)
for (
ContractDefinition const* contract:
ASTNode::filteredNodes<ContractDefinition>(pair.second.ast->nodes())
)
{
string fullyQualifiedName = *pair.second.ast->annotation().path + ":" + contract->name();
// Note that we now reference contracts by their fully qualified names, and
// thus contracts can only conflict if declared in the same source file. This
// should already cause a double-declaration error elsewhere.
if (!m_contracts.count(fullyQualifiedName))
m_contracts[fullyQualifiedName].contract = contract;
else
solAssert(
m_errorReporter.hasErrors(),
"Contract already present (name clash?), but no error was reported."
);
}
}
namespace
{
bool onlySafeExperimentalFeaturesActivated(set<ExperimentalFeature> const& features)
+8 -3
View File
@@ -90,7 +90,8 @@ public:
enum State {
Empty,
SourcesSet,
ParsingPerformed,
Parsed,
ParsedAndImported,
AnalysisPerformed,
CompilationSuccessful
};
@@ -216,11 +217,11 @@ public:
/// Parses and analyzes all source units that were added
/// @returns false on error.
bool parseAndAnalyze();
bool parseAndAnalyze(State _stopAfter = State::CompilationSuccessful);
/// Compiles the source units that were previously added and parsed.
/// @returns false on error.
bool compile();
bool compile(State _stopAfter = State::CompilationSuccessful);
/// @returns the list of sources (paths) used
std::vector<std::string> sourceNames() const;
@@ -373,6 +374,9 @@ private:
std::string applyRemapping(std::string const& _path, std::string const& _context);
void resolveImports();
/// Store the contract definitions in m_contracts.
void storeContractDefinitions();
/// @returns true if the source is requested to be compiled.
bool isRequestedSource(std::string const& _sourceName) const;
@@ -446,6 +450,7 @@ private:
ReadCallback::Callback m_readFile;
OptimiserSettings m_optimiserSettings;
RevertStrings m_revertStrings = RevertStrings::Default;
State m_stopAfter = State::CompilationSuccessful;
langutil::EVMVersion m_evmVersion;
smtutil::SMTSolverChoice m_enabledSMTSolvers;
std::map<std::string, std::set<std::string>> m_requestedContractNames;
+34 -13
View File
@@ -414,7 +414,7 @@ std::optional<Json::Value> checkAuxiliaryInputKeys(Json::Value const& _input)
std::optional<Json::Value> checkSettingsKeys(Json::Value const& _input)
{
static set<string> keys{"parserErrorRecovery", "debug", "evmVersion", "libraries", "metadata", "optimizer", "outputSelection", "remappings"};
static set<string> keys{"parserErrorRecovery", "debug", "evmVersion", "libraries", "metadata", "optimizer", "outputSelection", "remappings", "stopAfter"};
return checkKeys(_input, keys, "settings");
}
@@ -724,6 +724,17 @@ std::variant<StandardCompiler::InputsAndSettings, Json::Value> StandardCompiler:
if (auto result = checkSettingsKeys(settings))
return *result;
if (settings.isMember("stopAfter"))
{
if (!settings["stopAfter"].isString())
return formatFatalError("JSONError", "\"settings.stopAfter\" must be a string.");
if (settings["stopAfter"].asString() != "parsing")
return formatFatalError("JSONError", "Invalid value for \"settings.stopAfter\". Only valid value is \"parsing\".");
ret.stopAfter = CompilerStack::State::Parsed;
}
if (settings.isMember("parserErrorRecovery"))
{
if (!settings["parserErrorRecovery"].isBool())
@@ -849,6 +860,12 @@ std::variant<StandardCompiler::InputsAndSettings, Json::Value> StandardCompiler:
ret.outputSelection = std::move(outputSelection);
if (ret.stopAfter != CompilerStack::State::CompilationSuccessful && isBinaryRequested(ret.outputSelection))
return formatFatalError(
"JSONError",
"Requested output selection conflicts with \"settings.stopAfter\"."
);
return { std::move(ret) };
}
@@ -883,7 +900,7 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting
if (binariesRequested)
compilerStack.compile();
else
compilerStack.parseAndAnalyze();
compilerStack.parseAndAnalyze(_inputsAndSettings.stopAfter);
for (auto const& error: compilerStack.errors())
{
@@ -1005,7 +1022,10 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting
analysisPerformed = false;
/// Inconsistent state - stop here to receive error reports from users
if (((binariesRequested && !compilationSuccess) || !analysisPerformed) && errors.empty())
if (
((binariesRequested && !compilationSuccess) || !analysisPerformed) &&
(errors.empty() && _inputsAndSettings.stopAfter >= CompilerStack::State::AnalysisPerformed)
)
return formatFatalError("InternalCompilerError", "No error reported, but compilation failed.");
Json::Value output = Json::objectValue;
@@ -1021,16 +1041,17 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting
output["sources"] = Json::objectValue;
unsigned sourceIndex = 0;
for (string const& sourceName: analysisPerformed ? compilerStack.sourceNames() : vector<string>())
{
Json::Value sourceResult = Json::objectValue;
sourceResult["id"] = sourceIndex++;
if (isArtifactRequested(_inputsAndSettings.outputSelection, sourceName, "", "ast", wildcardMatchesExperimental))
sourceResult["ast"] = ASTJsonConverter(false, compilerStack.sourceIndices()).toJson(compilerStack.ast(sourceName));
if (isArtifactRequested(_inputsAndSettings.outputSelection, sourceName, "", "legacyAST", wildcardMatchesExperimental))
sourceResult["legacyAST"] = ASTJsonConverter(true, compilerStack.sourceIndices()).toJson(compilerStack.ast(sourceName));
output["sources"][sourceName] = sourceResult;
}
if (compilerStack.state() >= CompilerStack::State::Parsed && (!compilerStack.hasError() || _inputsAndSettings.parserErrorRecovery))
for (string const& sourceName: compilerStack.sourceNames())
{
Json::Value sourceResult = Json::objectValue;
sourceResult["id"] = sourceIndex++;
if (isArtifactRequested(_inputsAndSettings.outputSelection, sourceName, "", "ast", wildcardMatchesExperimental))
sourceResult["ast"] = ASTJsonConverter(false, compilerStack.state(), compilerStack.sourceIndices()).toJson(compilerStack.ast(sourceName));
if (isArtifactRequested(_inputsAndSettings.outputSelection, sourceName, "", "legacyAST", wildcardMatchesExperimental))
sourceResult["legacyAST"] = ASTJsonConverter(true, compilerStack.state(), compilerStack.sourceIndices()).toJson(compilerStack.ast(sourceName));
output["sources"][sourceName] = sourceResult;
}
Json::Value contractsOutput = Json::objectValue;
for (string const& contractName: analysisPerformed ? compilerStack.contractNames() : vector<string>())
+1
View File
@@ -60,6 +60,7 @@ private:
std::string language;
Json::Value errors;
bool parserErrorRecovery = false;
CompilerStack::State stopAfter = CompilerStack::State::CompilationSuccessful;
std::map<std::string, std::string> sources;
std::map<util::h256, std::string> smtLib2Responses;
langutil::EVMVersion evmVersion;