Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support experimental feature pragma #2690

Merged
merged 6 commits into from
Aug 10, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 39 additions & 4 deletions libsolidity/analysis/SyntaxChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <libsolidity/analysis/SyntaxChecker.h>
#include <memory>
#include <libsolidity/ast/AST.h>
#include <libsolidity/ast/ExperimentalFeatures.h>
#include <libsolidity/analysis/SemVerHandler.h>
#include <libsolidity/interface/ErrorReporter.h>
#include <libsolidity/interface/Version.h>
Expand All @@ -33,9 +34,10 @@ bool SyntaxChecker::checkSyntax(ASTNode const& _astRoot)
return Error::containsOnlyWarnings(m_errorReporter.errors());
}

bool SyntaxChecker::visit(SourceUnit const&)
bool SyntaxChecker::visit(SourceUnit const& _sourceUnit)
{
m_versionPragmaFound = false;
m_sourceUnit = &_sourceUnit;
return true;
}

Expand All @@ -57,15 +59,46 @@ void SyntaxChecker::endVisit(SourceUnit const& _sourceUnit)

m_errorReporter.warning(_sourceUnit.location(), errorString);
}
m_sourceUnit = nullptr;
}

bool SyntaxChecker::visit(PragmaDirective const& _pragma)
{
solAssert(!_pragma.tokens().empty(), "");
solAssert(_pragma.tokens().size() == _pragma.literals().size(), "");
if (_pragma.tokens()[0] != Token::Identifier || _pragma.literals()[0] != "solidity")
m_errorReporter.syntaxError(_pragma.location(), "Unknown pragma \"" + _pragma.literals()[0] + "\"");
else
if (_pragma.tokens()[0] != Token::Identifier)
m_errorReporter.syntaxError(_pragma.location(), "Invalid pragma \"" + _pragma.literals()[0] + "\"");
else if (_pragma.literals()[0] == "experimental")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Depending on the feature, this has to be done much earlier, probably best in the parser.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, confused that with SemanticAnalyzer.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, but that requires a few more helpers as the parser doesn't currently maintain what sourceunit it is in.

{
solAssert(m_sourceUnit, "");
vector<string> literals(_pragma.literals().begin() + 1, _pragma.literals().end());
if (literals.size() == 0)
m_errorReporter.syntaxError(
_pragma.location(),
"Experimental feature name is missing."
);
else if (literals.size() > 1)
m_errorReporter.syntaxError(
_pragma.location(),
"Stray arguments."
);
else
{
string const literal = literals[0];
if (literal.empty())
m_errorReporter.syntaxError(_pragma.location(), "Empty experimental feature name is invalid.");
else if (!ExperimentalFeatureNames.count(literal))
m_errorReporter.syntaxError(_pragma.location(), "Unsupported experimental feature name.");
else if (m_sourceUnit->annotation().experimentalFeatures.count(ExperimentalFeatureNames.at(literal)))
m_errorReporter.syntaxError(_pragma.location(), "Duplicate experimental feature name.");
else
{
m_sourceUnit->annotation().experimentalFeatures.insert(ExperimentalFeatureNames.at(literal));
m_errorReporter.warning(_pragma.location(), "Experimental features are turned on. Do not use experimental features on live deployments.");
}
}
}
else if (_pragma.literals()[0] == "solidity")
{
vector<Token::Value> tokens(_pragma.tokens().begin() + 1, _pragma.tokens().end());
vector<string> literals(_pragma.literals().begin() + 1, _pragma.literals().end());
Expand All @@ -81,6 +114,8 @@ bool SyntaxChecker::visit(PragmaDirective const& _pragma)
);
m_versionPragmaFound = true;
}
else
m_errorReporter.syntaxError(_pragma.location(), "Unknown pragma \"" + _pragma.literals()[0] + "\"");
return true;
}

Expand Down
2 changes: 2 additions & 0 deletions libsolidity/analysis/SyntaxChecker.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ class SyntaxChecker: private ASTConstVisitor
bool m_versionPragmaFound = false;

int m_inLoopDepth = 0;

SourceUnit const* m_sourceUnit = nullptr;
};

}
Expand Down
3 changes: 3 additions & 0 deletions libsolidity/ast/ASTAnnotations.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#pragma once

#include <libsolidity/ast/ASTForward.h>
#include <libsolidity/ast/ExperimentalFeatures.h>

#include <map>
#include <memory>
Expand Down Expand Up @@ -61,6 +62,8 @@ struct SourceUnitAnnotation: ASTAnnotation
std::string path;
/// The exported symbols (all global symbols).
std::map<ASTString, std::vector<Declaration const*>> exportedSymbols;
/// Experimental features.
std::set<ExperimentalFeature> experimentalFeatures;
};

struct ImportAnnotation: ASTAnnotation
Expand Down
35 changes: 35 additions & 0 deletions libsolidity/ast/ExperimentalFeatures.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
This file is part of solidity.

solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* List of experimental features.
*/

#pragma once

#include <map>

namespace dev
{
namespace solidity
{

enum class ExperimentalFeature {};

static const std::map<std::string, ExperimentalFeature> ExperimentalFeatureNames = {};

}
}
37 changes: 37 additions & 0 deletions test/libsolidity/SolidityNameAndTypeResolution.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6558,6 +6558,43 @@ BOOST_AUTO_TEST_CASE(library_function_without_implementation)
CHECK_ERROR(text, TypeError, "Internal library function must be implemented if declared.");
}

BOOST_AUTO_TEST_CASE(experimental_pragma)
{
char const* text = R"(
pragma experimental;
)";
CHECK_ERROR(text, SyntaxError, "Experimental feature name is missing.");
text = R"(
pragma experimental 123;
)";
CHECK_ERROR(text, SyntaxError, "Unsupported experimental feature name.");
text = R"(
pragma experimental unsupportedName;
)";
CHECK_ERROR(text, SyntaxError, "Unsupported experimental feature name.");
text = R"(
pragma experimental "unsupportedName";
)";
CHECK_ERROR(text, SyntaxError, "Unsupported experimental feature name.");
text = R"(
pragma experimental "";
)";
CHECK_ERROR(text, SyntaxError, "Empty experimental feature name is invalid.");
text = R"(
pragma experimental unsupportedName unsupportedName;
)";
CHECK_ERROR(text, SyntaxError, "Stray arguments.");
// text = R"(
// pragma experimental supportedName;
// )";
// CHECK_WARNING(text, "Experimental features are turned on. Do not use experimental features on live deployments.");
// text = R"(
// pragma experimental supportedName;
// pragma experimental supportedName;
// )";
// CHECK_ERROR(text, SyntaxError, "Duplicate experimental feature name.");
}

BOOST_AUTO_TEST_SUITE_END()

}
Expand Down