This commit is contained in:
Christian Parpart 2020-05-18 13:50:25 +02:00
parent 0e13a3ae3c
commit e1fcd53216
8 changed files with 156 additions and 120 deletions

View File

@ -160,6 +160,7 @@ namespace solidity::langutil
K(External, "external", 0) \
K(Fallback, "fallback", 0) \
K(For, "for", 0) \
K(From, "from", 0) \
K(Function, "function", 0) \
K(Hex, "hex", 0) \
K(If, "if", 0) \

View File

@ -34,6 +34,7 @@
#include <libsolutil/LazyInit.h>
#include <boost/noncopyable.hpp>
#include <boost/filesystem/path.hpp>
#include <json/json.h>
#include <memory>
@ -475,6 +476,23 @@ public:
m_abstract(_abstract)
{}
ContractDefinition(
int64_t _id,
SourceLocation const& _location,
boost::filesystem::path const& _jsonSourceFile
):
ContractDefinition{
_id,
_location,
{}, // name
{}, // StructuredDocumentation
{}, // InheritanceSpecifier[]
{} // body
}
{
m_jsonSourceFile = _jsonSourceFile;
}
void accept(ASTVisitor& _visitor) override;
void accept(ASTConstVisitor& _visitor) const override;
@ -531,11 +549,14 @@ public:
/// @returns the next constructor in the inheritance hierarchy.
FunctionDefinition const* nextConstructor(ContractDefinition const& _mostDerivedContract) const;
std::optional<boost::filesystem::path> jsonSourceFile() const noexcept { return m_jsonSourceFile; }
private:
std::vector<ASTPointer<InheritanceSpecifier>> m_baseContracts;
std::vector<ASTPointer<ASTNode>> m_subNodes;
ContractKind m_contractKind;
bool m_abstract{false};
std::optional<boost::filesystem::path> m_jsonSourceFile {std::nullopt};
util::LazyInit<std::vector<std::pair<util::FixedHash<4>, FunctionTypePointer>>> m_interfaceFunctionList[2];
util::LazyInit<std::vector<EventDefinition const*>> m_interfaceEvents;

View File

@ -68,6 +68,11 @@ map<string, ASTPointer<SourceUnit>> ASTJsonImporter::jsonToSourceUnit(map<string
return m_sourceUnits;
}
ASTPointer<ContractDefinition> ASTJsonImporter::jsonToContract(Json::Value const& _source)
{
return createContractDefinition(_source);
}
// ============ private ===========================
// =========== general creation functions ==============

View File

@ -48,6 +48,8 @@ public:
/// @returns map of sourcenames to their respective ASTs
std::map<std::string, ASTPointer<SourceUnit>> jsonToSourceUnit(std::map<std::string, Json::Value> const& _sourceList);
ASTPointer<ContractDefinition> jsonToContract(Json::Value const& _sourceList);
private:
// =========== general creation functions ==============

View File

@ -263,6 +263,8 @@ bool CompilerStack::parse()
m_sources[newPath].scanner = make_shared<Scanner>(CharStream(newContents, newPath));
sourcesToParse.push_back(newPath);
}
loadMissingInterfaces();
}
}
@ -272,6 +274,46 @@ bool CompilerStack::parse()
return !m_hasError;
}
void CompilerStack::loadMissingInterfaces()
{
for (auto const& sourcePair: m_sources)
{
ASTPointer<SourceUnit> const& source = sourcePair.second.ast;;
for (auto const& astNode: source->nodes())
{
if (auto* contract = dynamic_cast<ContractDefinition*>(astNode.get()))
{
if (auto const fileName = contract->jsonSourceFile(); fileName.has_value())
{
printf("%s needs replacement\n", fileName->string().c_str());
ReadCallback::Result result{false, string("File not supplied initially.")};
if (m_readFile)
result = m_readFile(ReadCallback::kindString(ReadCallback::Kind::ReadFile), fileName.value().string());
if (result.success)
{
string const& jsonString = result.responseOrErrorMessage;
printf("jsonString: %s\n", jsonString.c_str());
Json::Value json;
util::jsonParseStrict(jsonString, json, nullptr);
ASTPointer<ContractDefinition> jsonContract = ASTJsonImporter{m_evmVersion}.jsonToContract(json);
//TODO: contract = *jsonContract;
}
else
{
m_errorReporter.fatalParserError(
31415_error, // TODO
contract->location(),
"Cannot load JSON source."
);
}
}
}
}
}
}
void CompilerStack::importASTs(map<string, Json::Value> const& _sources)
{
if (m_stackState != Empty)

View File

@ -360,6 +360,8 @@ private:
std::string applyRemapping(std::string const& _path, std::string const& _context);
void resolveImports();
void loadMissingInterfaces();
/// @returns true if the source is requested to be compiled.
bool isRequestedSource(std::string const& _sourceName) const;

View File

@ -95,8 +95,8 @@ ASTPointer<SourceUnit> Parser::parse(shared_ptr<Scanner> const& _scanner)
nodes.push_back(parseImportDirective());
break;
case Token::Interface:
// nodes.push_back(parseInterfaceDefinition());
// break;
nodes.push_back(parseInterfaceDefinition());
break;
case Token::Abstract:
case Token::Contract:
case Token::Library:
@ -296,20 +296,35 @@ ASTPointer<ContractDefinition> Parser::parseInterfaceDefinition()
{
// interfaceDefinition
// : 'interface' identifier 'from' StringLiteralFragment
// | 'interface' identifier 'as' AbiString
// | 'interface' identifier contractInheritanceDefinition? contractBody ;
m_scanner->next();
RecursionGuard recursionGuard(*this);
ASTNodeFactory nodeFactory(*this);
m_scanner->next();
ASTPointer<ASTString> name = expectIdentifierToken();
ASTPointer<StructuredDocumentation> documentation = parseStructuredDocumentation();
vector<ASTPointer<InheritanceSpecifier>> baseContracts;
vector<ASTPointer<ASTNode>> subNodes;//TODO = parseContractBody();
if (m_scanner->currentToken() == Token::From)
{
m_scanner->next();
if (m_scanner->currentToken() != Token::StringLiteral)
fatalParserError(6845_error, "Expected string literal fragment.");
boost::filesystem::path const jsonSourceFileName {*getLiteralAndAdvance()};
nodeFactory.markEndPosition();
expectToken(Token::Semicolon);
return nodeFactory.createNode<ContractDefinition>(jsonSourceFileName);
}
baseContracts = parseContractInheritanceList();
expectToken(Token::LBrace);
vector<ASTPointer<ASTNode>> subNodes = parseContractBody();
nodeFactory.markEndPosition();
expectToken(Token::RBrace);
return nodeFactory.createNode<ContractDefinition>(
name,
@ -321,6 +336,21 @@ ASTPointer<ContractDefinition> Parser::parseInterfaceDefinition()
);
}
vector<ASTPointer<InheritanceSpecifier>> Parser::parseContractInheritanceList()
{
vector<ASTPointer<InheritanceSpecifier>> baseContracts;
if (m_scanner->currentToken() == Token::Is)
do
{
m_scanner->next();
baseContracts.push_back(parseInheritanceSpecifier());
}
while (m_scanner->currentToken() == Token::Comma);
return baseContracts;
}
ASTPointer<ContractDefinition> Parser::parseContractDefinition()
{
RecursionGuard recursionGuard(*this);
@ -335,57 +365,10 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition()
documentation = parseStructuredDocumentation();
contractKind = parseContractKind();
name = expectIdentifierToken();
if (m_scanner->currentToken() == Token::Is)
do
{
m_scanner->next();
baseContracts.push_back(parseInheritanceSpecifier());
}
while (m_scanner->currentToken() == Token::Comma);
#if 0
parseContractBody(subNodes);
//subNodes = parseContractBody();
#else
baseContracts = parseContractInheritanceList();
expectToken(Token::LBrace);
while (true)
{
Token currentTokenValue = m_scanner->currentToken();
if (currentTokenValue == Token::RBrace)
break;
else if (
(currentTokenValue == Token::Function && m_scanner->peekNextToken() != Token::LParen) ||
currentTokenValue == Token::Constructor ||
currentTokenValue == Token::Receive ||
currentTokenValue == Token::Fallback
)
subNodes.push_back(parseFunctionDefinition());
else if (currentTokenValue == Token::Struct)
subNodes.push_back(parseStructDefinition());
else if (currentTokenValue == Token::Enum)
subNodes.push_back(parseEnumDefinition());
else if (
currentTokenValue == Token::Identifier ||
currentTokenValue == Token::Mapping ||
TokenTraits::isElementaryTypeName(currentTokenValue) ||
(currentTokenValue == Token::Function && m_scanner->peekNextToken() == Token::LParen)
)
{
VarDeclParserOptions options;
options.isStateVariable = true;
options.allowInitialValue = true;
subNodes.push_back(parseVariableDeclaration(options));
expectToken(Token::Semicolon);
}
else if (currentTokenValue == Token::Modifier)
subNodes.push_back(parseModifierDefinition());
else if (currentTokenValue == Token::Event)
subNodes.push_back(parseEventDefinition());
else if (currentTokenValue == Token::Using)
subNodes.push_back(parseUsingDirective());
else
fatalParserError(9182_error, "Function, variable, struct or modifier declaration expected.");
}
#endif
subNodes = parseContractBody();
}
catch (FatalError const&)
{
@ -395,8 +378,6 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition()
m_errorReporter.hasExcessiveErrors()
)
BOOST_THROW_EXCEPTION(FatalError()); /* Don't try to recover here. */
nodeFactory.markEndPosition();
expectTokenOrConsumeUntil(Token::RBrace, "ContractDefinition");
m_inParserRecovery = true;
}
nodeFactory.markEndPosition();
@ -414,70 +395,52 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition()
);
}
void Parser::parseContractBody(vector<ASTPointer<ASTNode>>& subNodes)
/// parses the contract body but (due to error recovery strategies) *without* surrounding
/// curly braces.
vector<ASTPointer<ASTNode>> Parser::parseContractBody()
{
//vector<ASTPointer<ASTNode>> subNodes;
vector<ASTPointer<ASTNode>> subNodes;
try
while (true)
{
expectToken(Token::LBrace);
while (true)
{
Token currentTokenValue = m_scanner->currentToken();
if (currentTokenValue == Token::RBrace)
break;
else if (
(currentTokenValue == Token::Function && m_scanner->peekNextToken() != Token::LParen) ||
currentTokenValue == Token::Constructor ||
currentTokenValue == Token::Receive ||
currentTokenValue == Token::Fallback
)
subNodes.push_back(parseFunctionDefinition());
else if (currentTokenValue == Token::Struct)
subNodes.push_back(parseStructDefinition());
else if (currentTokenValue == Token::Enum)
subNodes.push_back(parseEnumDefinition());
else if (
currentTokenValue == Token::Identifier ||
currentTokenValue == Token::Mapping ||
TokenTraits::isElementaryTypeName(currentTokenValue) ||
(currentTokenValue == Token::Function && m_scanner->peekNextToken() == Token::LParen)
)
{
VarDeclParserOptions options;
options.isStateVariable = true;
options.allowInitialValue = true;
subNodes.push_back(parseVariableDeclaration(options));
expectToken(Token::Semicolon);
}
else if (currentTokenValue == Token::Modifier)
subNodes.push_back(parseModifierDefinition());
else if (currentTokenValue == Token::Event)
subNodes.push_back(parseEventDefinition());
else if (currentTokenValue == Token::Using)
subNodes.push_back(parseUsingDirective());
else
fatalParserError(9182_error, "Function, variable, struct or modifier declaration expected.");
}
}
catch (FatalError const&)
{
printf("FatalError: in parser recovery\n");
if (
!m_errorReporter.hasErrors() ||
!m_parserErrorRecovery ||
m_errorReporter.hasExcessiveErrors()
Token currentTokenValue = m_scanner->currentToken();
if (currentTokenValue == Token::RBrace)
break;
else if (
(currentTokenValue == Token::Function && m_scanner->peekNextToken() != Token::LParen) ||
currentTokenValue == Token::Constructor ||
currentTokenValue == Token::Receive ||
currentTokenValue == Token::Fallback
)
BOOST_THROW_EXCEPTION(FatalError()); /* Don't try to recover here. */
m_inParserRecovery = true;
subNodes.push_back(parseFunctionDefinition());
else if (currentTokenValue == Token::Struct)
subNodes.push_back(parseStructDefinition());
else if (currentTokenValue == Token::Enum)
subNodes.push_back(parseEnumDefinition());
else if (
currentTokenValue == Token::Identifier ||
currentTokenValue == Token::Mapping ||
TokenTraits::isElementaryTypeName(currentTokenValue) ||
(currentTokenValue == Token::Function && m_scanner->peekNextToken() == Token::LParen)
)
{
VarDeclParserOptions options;
options.isStateVariable = true;
options.allowInitialValue = true;
subNodes.push_back(parseVariableDeclaration(options));
expectToken(Token::Semicolon);
}
else if (currentTokenValue == Token::Modifier)
subNodes.push_back(parseModifierDefinition());
else if (currentTokenValue == Token::Event)
subNodes.push_back(parseEventDefinition());
else if (currentTokenValue == Token::Using)
subNodes.push_back(parseUsingDirective());
else
fatalParserError(9182_error, "Function, variable, struct or modifier declaration expected.");
}
if (m_inParserRecovery)
expectTokenOrConsumeUntil(Token::RBrace, "ContractDefinition");
else
expectToken(Token::RBrace);
//return subNodes;
return subNodes;
}
ASTPointer<InheritanceSpecifier> Parser::parseInheritanceSpecifier()

View File

@ -87,9 +87,9 @@ private:
/// result.second is set to true, if an abstract contract was parsed, false otherwise.
std::pair<ContractKind, bool> parseContractKind();
ASTPointer<ContractDefinition> parseContractDefinition();
std::vector<ASTPointer<InheritanceSpecifier>> parseContractInheritanceList();
ASTPointer<ContractDefinition> parseInterfaceDefinition();
//std::vector<ASTPointer<ASTNode>> parseContractBody();
void parseContractBody(std::vector<ASTPointer<ASTNode>>& _result);
std::vector<ASTPointer<ASTNode>> parseContractBody();
ASTPointer<InheritanceSpecifier> parseInheritanceSpecifier();
Visibility parseVisibilitySpecifier();
ASTPointer<OverrideSpecifier> parseOverrideSpecifier();