mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Introduce solidity-next pragma
Exclude pragma experimental error from ANTLR tests Test for first pragma after non-pragma declaration Resolve import pragmas Change pragma name from next to solidity Add Changelog entries Address review comments
This commit is contained in:
@@ -167,9 +167,14 @@ public:
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
std::optional<std::string> _licenseString,
|
||||
std::vector<ASTPointer<ASTNode>> _nodes
|
||||
std::vector<ASTPointer<ASTNode>> _nodes,
|
||||
bool _experimentalSolidity
|
||||
):
|
||||
ASTNode(_id, _location), m_licenseString(std::move(_licenseString)), m_nodes(std::move(_nodes)) {}
|
||||
ASTNode(_id, _location),
|
||||
m_licenseString(std::move(_licenseString)),
|
||||
m_nodes(std::move(_nodes)),
|
||||
m_experimentalSolidity(_experimentalSolidity)
|
||||
{}
|
||||
|
||||
void accept(ASTVisitor& _visitor) override;
|
||||
void accept(ASTConstVisitor& _visitor) const override;
|
||||
@@ -180,10 +185,12 @@ public:
|
||||
|
||||
/// @returns a set of referenced SourceUnits. Recursively if @a _recurse is true.
|
||||
std::set<SourceUnit const*> referencedSourceUnits(bool _recurse = false, std::set<SourceUnit const*> _skipList = std::set<SourceUnit const*>()) const;
|
||||
bool experimentalSolidity() const { return m_experimentalSolidity; }
|
||||
|
||||
private:
|
||||
std::optional<std::string> m_licenseString;
|
||||
std::vector<ASTPointer<ASTNode>> m_nodes;
|
||||
bool m_experimentalSolidity = false;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -214,9 +214,12 @@ bool ASTJsonExporter::visit(SourceUnit const& _node)
|
||||
{
|
||||
std::vector<pair<string, Json::Value>> attributes = {
|
||||
make_pair("license", _node.licenseString() ? Json::Value(*_node.licenseString()) : Json::nullValue),
|
||||
make_pair("nodes", toJson(_node.nodes()))
|
||||
make_pair("nodes", toJson(_node.nodes())),
|
||||
};
|
||||
|
||||
if (_node.experimentalSolidity())
|
||||
attributes.emplace_back("experimentalSolidity", Json::Value(_node.experimentalSolidity()));
|
||||
|
||||
if (_node.annotation().exportedSymbols.set())
|
||||
{
|
||||
Json::Value exportedSymbols = Json::objectValue;
|
||||
|
||||
@@ -271,11 +271,15 @@ ASTPointer<SourceUnit> ASTJsonImporter::createSourceUnit(Json::Value const& _nod
|
||||
if (_node.isMember("license") && !_node["license"].isNull())
|
||||
license = _node["license"].asString();
|
||||
|
||||
bool experimentalSolidity = false;
|
||||
if (_node.isMember("experimentalSolidity") && !_node["experimentalSolidity"].isNull())
|
||||
experimentalSolidity = _node["experimentalSolidity"].asBool();
|
||||
|
||||
vector<ASTPointer<ASTNode>> nodes;
|
||||
for (auto& child: member(_node, "nodes"))
|
||||
nodes.emplace_back(convertJsonToASTNode(child));
|
||||
|
||||
ASTPointer<SourceUnit> tmp = createASTNode<SourceUnit>(_node, license, nodes);
|
||||
ASTPointer<SourceUnit> tmp = createASTNode<SourceUnit>(_node, license, nodes, experimentalSolidity);
|
||||
tmp->annotation().path = _srcName;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
@@ -32,7 +32,8 @@ enum class ExperimentalFeature
|
||||
ABIEncoderV2, // new ABI encoder that makes use of Yul
|
||||
SMTChecker,
|
||||
Test,
|
||||
TestOnlyAnalysis
|
||||
TestOnlyAnalysis,
|
||||
Solidity
|
||||
};
|
||||
|
||||
static std::set<ExperimentalFeature> const ExperimentalFeatureWithoutWarning =
|
||||
@@ -48,6 +49,7 @@ static std::map<std::string, ExperimentalFeature> const ExperimentalFeatureNames
|
||||
{ "SMTChecker", ExperimentalFeature::SMTChecker },
|
||||
{ "__test", ExperimentalFeature::Test },
|
||||
{ "__testOnlyAnalysis", ExperimentalFeature::TestOnlyAnalysis },
|
||||
{ "solidity", ExperimentalFeature::Solidity }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -429,7 +429,9 @@ bool CompilerStack::analyze()
|
||||
{
|
||||
if (m_stackState != ParsedAndImported || m_stackState >= AnalysisPerformed)
|
||||
solThrow(CompilerError, "Must call analyze only after parsing was performed.");
|
||||
resolveImports();
|
||||
|
||||
if (!resolveImports())
|
||||
return false;
|
||||
|
||||
for (Source const* source: m_sourceOrder)
|
||||
if (source->ast)
|
||||
@@ -1175,7 +1177,7 @@ string CompilerStack::applyRemapping(string const& _path, string const& _context
|
||||
return m_importRemapper.apply(_path, _context);
|
||||
}
|
||||
|
||||
void CompilerStack::resolveImports()
|
||||
bool CompilerStack::resolveImports()
|
||||
{
|
||||
solAssert(m_stackState == ParsedAndImported, "");
|
||||
|
||||
@@ -1200,11 +1202,34 @@ void CompilerStack::resolveImports()
|
||||
sourceOrder.push_back(_source);
|
||||
};
|
||||
|
||||
vector<PragmaDirective const*> experimentalPragmaDirectives;
|
||||
for (auto const& sourcePair: m_sources)
|
||||
{
|
||||
if (isRequestedSource(sourcePair.first))
|
||||
toposort(&sourcePair.second);
|
||||
if (sourcePair.second.ast && sourcePair.second.ast->experimentalSolidity())
|
||||
for (ASTPointer<ASTNode> const& node: sourcePair.second.ast->nodes())
|
||||
if (PragmaDirective const* pragma = dynamic_cast<PragmaDirective*>(node.get()))
|
||||
if (pragma->literals().size() >=2 && pragma->literals()[0] == "experimental" && pragma->literals()[1] == "solidity")
|
||||
{
|
||||
experimentalPragmaDirectives.push_back(pragma);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!experimentalPragmaDirectives.empty() && experimentalPragmaDirectives.size() != m_sources.size())
|
||||
{
|
||||
for (auto &&pragma: experimentalPragmaDirectives)
|
||||
m_errorReporter.parserError(
|
||||
2141_error,
|
||||
pragma->location(),
|
||||
"File declares \"pragma experimental solidity\". If you want to enable the experimental mode, all source units must include the pragma."
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
swap(m_sourceOrder, sourceOrder);
|
||||
return true;
|
||||
}
|
||||
|
||||
void CompilerStack::storeContractDefinitions()
|
||||
|
||||
@@ -399,7 +399,7 @@ private:
|
||||
/// @returns the newly loaded sources.
|
||||
StringMap loadMissingSources(SourceUnit const& _ast);
|
||||
std::string applyRemapping(std::string const& _path, std::string const& _context);
|
||||
void resolveImports();
|
||||
bool resolveImports();
|
||||
|
||||
/// Store the contract definitions in m_contracts.
|
||||
void storeContractDefinitions();
|
||||
|
||||
@@ -94,14 +94,18 @@ ASTPointer<SourceUnit> Parser::parse(CharStream& _charStream)
|
||||
m_recursionDepth = 0;
|
||||
m_scanner = make_shared<Scanner>(_charStream);
|
||||
ASTNodeFactory nodeFactory(*this);
|
||||
m_experimentalSolidityEnabledInCurrentSourceUnit = false;
|
||||
|
||||
vector<ASTPointer<ASTNode>> nodes;
|
||||
while (m_scanner->currentToken() == Token::Pragma)
|
||||
nodes.push_back(parsePragmaDirective(false));
|
||||
|
||||
while (m_scanner->currentToken() != Token::EOS)
|
||||
{
|
||||
switch (m_scanner->currentToken())
|
||||
{
|
||||
case Token::Pragma:
|
||||
nodes.push_back(parsePragmaDirective());
|
||||
nodes.push_back(parsePragmaDirective(true));
|
||||
break;
|
||||
case Token::Import:
|
||||
nodes.push_back(parseImportDirective());
|
||||
@@ -150,7 +154,7 @@ ASTPointer<SourceUnit> Parser::parse(CharStream& _charStream)
|
||||
}
|
||||
}
|
||||
solAssert(m_recursionDepth == 0, "");
|
||||
return nodeFactory.createNode<SourceUnit>(findLicenseString(nodes), nodes);
|
||||
return nodeFactory.createNode<SourceUnit>(findLicenseString(nodes), nodes, m_experimentalSolidityEnabledInCurrentSourceUnit);
|
||||
}
|
||||
catch (FatalError const&)
|
||||
{
|
||||
@@ -203,7 +207,7 @@ ASTPointer<StructuredDocumentation> Parser::parseStructuredDocumentation()
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ASTPointer<PragmaDirective> Parser::parsePragmaDirective()
|
||||
ASTPointer<PragmaDirective> Parser::parsePragmaDirective(bool const _finishedParsingTopLevelPragmas)
|
||||
{
|
||||
RecursionGuard recursionGuard(*this);
|
||||
// pragma anything* ;
|
||||
@@ -213,6 +217,7 @@ ASTPointer<PragmaDirective> Parser::parsePragmaDirective()
|
||||
expectToken(Token::Pragma);
|
||||
vector<string> literals;
|
||||
vector<Token> tokens;
|
||||
|
||||
do
|
||||
{
|
||||
Token token = m_scanner->currentToken();
|
||||
@@ -241,6 +246,13 @@ ASTPointer<PragmaDirective> Parser::parsePragmaDirective()
|
||||
);
|
||||
}
|
||||
|
||||
if (literals.size() >= 2 && literals[0] == "experimental" && literals[1] == "solidity")
|
||||
{
|
||||
if (_finishedParsingTopLevelPragmas)
|
||||
fatalParserError(8185_error, "Experimental pragma \"solidity\" can only be set at the beginning of the source unit.");
|
||||
m_experimentalSolidityEnabledInCurrentSourceUnit = true;
|
||||
}
|
||||
|
||||
return nodeFactory.createNode<PragmaDirective>(tokens, literals);
|
||||
}
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ private:
|
||||
///@name Parsing functions for the AST nodes
|
||||
void parsePragmaVersion(langutil::SourceLocation const& _location, std::vector<Token> const& _tokens, std::vector<std::string> const& _literals);
|
||||
ASTPointer<StructuredDocumentation> parseStructuredDocumentation();
|
||||
ASTPointer<PragmaDirective> parsePragmaDirective();
|
||||
ASTPointer<PragmaDirective> parsePragmaDirective(bool _finishedParsingTopLevelPragmas);
|
||||
ASTPointer<ImportDirective> parseImportDirective();
|
||||
/// @returns an std::pair<ContractKind, bool>, where
|
||||
/// result.second is set to true, if an abstract contract was parsed, false otherwise.
|
||||
@@ -227,6 +227,8 @@ private:
|
||||
langutil::EVMVersion m_evmVersion;
|
||||
/// Counter for the next AST node ID
|
||||
int64_t m_currentNodeID = 0;
|
||||
/// Flag that indicates whether experimental mode is enabled in the current source unit
|
||||
bool m_experimentalSolidityEnabledInCurrentSourceUnit = false;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user