mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
WIP-2
This commit is contained in:
parent
0e13a3ae3c
commit
e1fcd53216
@ -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) \
|
||||
|
@ -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;
|
||||
|
@ -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 ==============
|
||||
|
@ -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 ==============
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user