Skip to content

Commit

Permalink
Add flag --ast-json-no-compile.
Browse files Browse the repository at this point in the history
This flag allows the compiler to receive a file, parse and analyze it, without fetching the imports, without compiling it, and returns the AST JSON of the file.
This is useful for parsing for imports and other key values of the Contract where compilation is not required
  • Loading branch information
jcaracciolo committed Apr 21, 2020
1 parent 73e06a4 commit 86b46f7
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 13 deletions.
2 changes: 1 addition & 1 deletion libsolidity/analysis/NameAndTypeResolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,7 @@ void DeclarationRegistrationHelper::endVisit(SourceUnit& _sourceUnit)
bool DeclarationRegistrationHelper::visit(ImportDirective& _import)
{
SourceUnit const* importee = _import.annotation().sourceUnit;
solAssert(!!importee, "");
// solAssert(!!importee, ""); Not sure about this Assert, Source unit will be null when not processing the imports
if (!m_scopes[importee])
m_scopes[importee] = make_shared<DeclarationContainer>(nullptr, m_scopes[nullptr].get());
m_scopes[&_import] = m_scopes[importee];
Expand Down
7 changes: 4 additions & 3 deletions libsolidity/ast/ASTJsonConverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ bool ASTJsonConverter::visit(ImportDirective const& _node)
std::vector<pair<string, Json::Value>> attributes = {
make_pair("file", _node.path()),
make_pair("absolutePath", _node.annotation().absolutePath),
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()))
};
attributes.emplace_back("unitAlias", _node.name());
Expand Down Expand Up @@ -363,7 +363,7 @@ bool ASTJsonConverter::visit(FunctionDefinition const& _node)
make_pair("implemented", _node.isImplemented()),
make_pair("scope", idOrNull(_node.scope()))
};
if (_node.isPartOfExternalInterface())
if (_node.scope() && _node.isPartOfExternalInterface())
attributes.emplace_back("functionSelector", _node.externalIdentifierHex());
if (!_node.annotation().baseFunctions.empty())
attributes.emplace_back(make_pair("baseFunctions", getContainerIds(_node.annotation().baseFunctions, true)));
Expand All @@ -388,7 +388,7 @@ bool ASTJsonConverter::visit(VariableDeclaration const& _node)
make_pair("scope", idOrNull(_node.scope())),
make_pair("typeDescriptions", typePointerToJson(_node.annotation().type, true))
};
if (_node.isStateVariable() && _node.isPublic())
if (_node.scope() && _node.isStateVariable() && _node.isPublic())
attributes.emplace_back("functionSelector", _node.externalIdentifierHex());
if (m_inEvent)
attributes.emplace_back("indexed", _node.isIndexed());
Expand Down Expand Up @@ -896,6 +896,7 @@ string ASTJsonConverter::functionCallKind(FunctionCallKind _kind)
case FunctionCallKind::StructConstructorCall:
return "structConstructorCall";
default:
return "unset";
solAssert(false, "Unknown kind of function call.");
}
}
Expand Down
26 changes: 19 additions & 7 deletions libsolidity/interface/CompilerStack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,10 @@ void CompilerStack::reset(bool _keepSettings)
TypeProvider::reset();
}

void CompilerStack::setOnlyParsing(bool _onlyParsing) {
m_onlyParsing = _onlyParsing;
}

void CompilerStack::setSources(StringMap _sources)
{
if (m_stackState == SourcesSet)
Expand Down Expand Up @@ -259,10 +263,12 @@ bool CompilerStack::parse()
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_onlyParsing) {
string const& newPath = newSource.first;
string const& newContents = newSource.second;
m_sources[newPath].scanner = make_shared<Scanner>(CharStream(newContents, newPath));
sourcesToParse.push_back(newPath);
}
}
}
}
Expand Down Expand Up @@ -465,6 +471,9 @@ bool CompilerStack::analyze()
bool CompilerStack::parseAndAnalyze()
{
bool success = parse();
if(m_onlyParsing)
return success;

if (success || m_parserErrorRecovery)
success = analyze();
return success;
Expand Down Expand Up @@ -534,8 +543,8 @@ void CompilerStack::link()

vector<string> CompilerStack::contractNames() const
{
if (m_stackState < AnalysisPerformed)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
// if (m_stackState < AnalysisPerformed)
// BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
vector<string> contractNames;
for (auto const& contract: m_contracts)
contractNames.push_back(contract.first);
Expand Down Expand Up @@ -937,7 +946,7 @@ StringMap CompilerStack::loadMissingSources(SourceUnit const& _ast, std::string
// as seen globally.
importPath = applyRemapping(importPath, _sourcePath);
import->annotation().absolutePath = importPath;
if (m_sources.count(importPath) || newSources.count(importPath))
if (m_sources.count(importPath) || newSources.count(importPath) || m_onlyParsing)
continue;

ReadCallback::Result result{false, string("File not supplied initially.")};
Expand Down Expand Up @@ -1023,6 +1032,9 @@ void CompilerStack::resolveImports()
if (ImportDirective const* import = dynamic_cast<ImportDirective*>(node.get()))
{
string const& path = import->annotation().absolutePath;
if(!m_sources.count(path)) {
continue;
}
solAssert(m_sources.count(path), "");
import->annotation().sourceUnit = m_sources[path].ast.get();
toposort(&m_sources[path]);
Expand Down
4 changes: 4 additions & 0 deletions libsolidity/interface/CompilerStack.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,9 @@ class CompilerStack: boost::noncopyable
/// @param _metadataHash can be IPFS, Bzzr1, None
void setMetadataHash(MetadataHash _metadataHash);

/// Sets the compiler in only parsing mode. No imports will be processed, compilation will be skipped.
void setOnlyParsing(bool _onlyParsing);

/// Sets the sources. Must be set before parsing.
void setSources(StringMap _sources);

Expand Down Expand Up @@ -461,6 +464,7 @@ class CompilerStack: boost::noncopyable
/// If this is true, the stack will refuse to generate code.
bool m_hasError = false;
bool m_release = VersionIsRelease;
bool m_onlyParsing = false;
};

}
15 changes: 13 additions & 2 deletions solc/CommandLineInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ static string const g_strAsmJson = "asm-json";
static string const g_strAssemble = "assemble";
static string const g_strAst = "ast";
static string const g_strAstJson = "ast-json";
static string const g_strAstJsonNoCompile = "ast-json-no-compile";
static string const g_strAstCompactJson = "ast-compact-json";
static string const g_strBinary = "bin";
static string const g_strBinaryRuntime = "bin-runtime";
Expand Down Expand Up @@ -182,6 +183,7 @@ static string const g_argAsmJson = g_strAsmJson;
static string const g_argAssemble = g_strAssemble;
static string const g_argAstCompactJson = g_strAstCompactJson;
static string const g_argAstJson = g_strAstJson;
static string const g_argAstJsonNoCompile = g_strAstJsonNoCompile;
static string const g_argBinary = g_strBinary;
static string const g_argBinaryRuntime = g_strBinaryRuntime;
static string const g_argCombinedJson = g_strCombinedJson;
Expand Down Expand Up @@ -291,6 +293,7 @@ static bool needsHumanTargetedStdout(po::variables_map const& _args)
g_argAsm,
g_argAsmJson,
g_argAstJson,
g_argAstJsonNoCompile,
g_argBinary,
g_argBinaryRuntime,
g_argMetadata,
Expand Down Expand Up @@ -837,6 +840,7 @@ Allowed options)",
po::options_description outputComponents("Output Components");
outputComponents.add_options()
(g_argAstJson.c_str(), "AST of all source files in JSON format.")
(g_argAstJsonNoCompile.c_str(), "AST of the single source file, no imports or compilation done, in JSON format.")
(g_argAstCompactJson.c_str(), "AST of all source files in a compact JSON format.")
(g_argAsm.c_str(), "EVM assembly of the contracts.")
(g_argAsmJson.c_str(), "EVM assembly of the contracts in JSON format.")
Expand Down Expand Up @@ -1136,6 +1140,7 @@ bool CommandLineInterface::processInput()
}

m_compiler = make_unique<CompilerStack>(fileReader);
m_compiler->setOnlyParsing(m_args.count(g_argAstJsonNoCompile));

unique_ptr<SourceReferenceFormatter> formatter;
if (m_args.count(g_argOldReporter))
Expand Down Expand Up @@ -1348,7 +1353,7 @@ void CommandLineInterface::handleAst(string const& _argStr)
{
string title;

if (_argStr == g_argAstJson)
if (_argStr == g_argAstJson || _argStr == g_argAstJsonNoCompile)
title = "JSON AST:";
else if (_argStr == g_argAstCompactJson)
title = "JSON AST (compact format):";
Expand All @@ -1374,7 +1379,7 @@ void CommandLineInterface::handleAst(string const& _argStr)
gasCosts[it.first] += it.second;
}

bool legacyFormat = !m_args.count(g_argAstCompactJson);
bool legacyFormat = !m_args.count(g_argAstCompactJson) && !m_args.count(g_argAstJsonNoCompile) ;
if (m_args.count(g_argOutputDir))
{
for (auto const& sourceCode: m_sourceCodes)
Expand Down Expand Up @@ -1631,6 +1636,12 @@ void CommandLineInterface::outputCompilationResults()
// do we need AST output?
handleAst(g_argAstJson);
handleAst(g_argAstCompactJson);
handleAst(g_argAstJsonNoCompile);

if(m_args.count(g_argAstJsonNoCompile)) {
//Done here
return;
}

if (!m_compiler->compilationSuccessful())
{
Expand Down

0 comments on commit 86b46f7

Please sign in to comment.