Parse "virtual" keyword

This commit is contained in:
Mathias Baumann 2019-10-30 14:34:37 +01:00
parent 8569fe7764
commit 7d4e4b6088
8 changed files with 85 additions and 9 deletions

View File

@ -189,6 +189,7 @@ namespace langutil
K(Using, "using", 0) \ K(Using, "using", 0) \
K(Var, "var", 0) \ K(Var, "var", 0) \
K(View, "view", 0) \ K(View, "view", 0) \
K(Virtual, "virtual", 0) \
K(While, "while", 0) \ K(While, "while", 0) \
\ \
/* Ether subdenominations */ \ /* Ether subdenominations */ \
@ -264,7 +265,6 @@ namespace langutil
K(Typedef, "typedef", 0) \ K(Typedef, "typedef", 0) \
K(TypeOf, "typeof", 0) \ K(TypeOf, "typeof", 0) \
K(Unchecked, "unchecked", 0) \ K(Unchecked, "unchecked", 0) \
K(Virtual, "virtual", 0) \
\ \
/* Illegal token - not able to scan. */ \ /* Illegal token - not able to scan. */ \
T(Illegal, "ILLEGAL", 0) \ T(Illegal, "ILLEGAL", 0) \
@ -313,7 +313,7 @@ namespace TokenTraits
constexpr bool isEtherSubdenomination(Token op) { return op == Token::SubWei || op == Token::SubSzabo || op == Token::SubFinney || op == Token::SubEther; } constexpr bool isEtherSubdenomination(Token op) { return op == Token::SubWei || op == Token::SubSzabo || op == Token::SubFinney || op == Token::SubEther; }
constexpr bool isTimeSubdenomination(Token op) { return op == Token::SubSecond || op == Token::SubMinute || op == Token::SubHour || op == Token::SubDay || op == Token::SubWeek || op == Token::SubYear; } constexpr bool isTimeSubdenomination(Token op) { return op == Token::SubSecond || op == Token::SubMinute || op == Token::SubHour || op == Token::SubDay || op == Token::SubWeek || op == Token::SubYear; }
constexpr bool isReservedKeyword(Token op) { return (Token::Abstract <= op && op <= Token::Virtual); } constexpr bool isReservedKeyword(Token op) { return (Token::Abstract <= op && op <= Token::Unchecked); }
inline Token AssignmentToBinaryOp(Token op) inline Token AssignmentToBinaryOp(Token op)
{ {

View File

@ -604,13 +604,15 @@ public:
ASTPointer<ASTString> const& _name, ASTPointer<ASTString> const& _name,
Declaration::Visibility _visibility, Declaration::Visibility _visibility,
ASTPointer<ParameterList> const& _parameters, ASTPointer<ParameterList> const& _parameters,
bool _isVirtual = false,
ASTPointer<OverrideSpecifier> const& _overrides = nullptr, ASTPointer<OverrideSpecifier> const& _overrides = nullptr,
ASTPointer<ParameterList> const& _returnParameters = ASTPointer<ParameterList>() ASTPointer<ParameterList> const& _returnParameters = ASTPointer<ParameterList>()
): ):
Declaration(_location, _name, _visibility), Declaration(_location, _name, _visibility),
m_parameters(_parameters), m_parameters(_parameters),
m_overrides(_overrides), m_overrides(_overrides),
m_returnParameters(_returnParameters) m_returnParameters(_returnParameters),
m_isVirtual(_isVirtual)
{ {
} }
@ -624,6 +626,7 @@ protected:
ASTPointer<ParameterList> m_parameters; ASTPointer<ParameterList> m_parameters;
ASTPointer<OverrideSpecifier> m_overrides; ASTPointer<OverrideSpecifier> m_overrides;
ASTPointer<ParameterList> m_returnParameters; ASTPointer<ParameterList> m_returnParameters;
bool m_isVirtual;
}; };
/** /**
@ -661,6 +664,7 @@ public:
Declaration::Visibility _visibility, Declaration::Visibility _visibility,
StateMutability _stateMutability, StateMutability _stateMutability,
Token _kind, Token _kind,
bool _isVirtual,
ASTPointer<OverrideSpecifier> const& _overrides, ASTPointer<OverrideSpecifier> const& _overrides,
ASTPointer<ASTString> const& _documentation, ASTPointer<ASTString> const& _documentation,
ASTPointer<ParameterList> const& _parameters, ASTPointer<ParameterList> const& _parameters,
@ -668,7 +672,7 @@ public:
ASTPointer<ParameterList> const& _returnParameters, ASTPointer<ParameterList> const& _returnParameters,
ASTPointer<Block> const& _body ASTPointer<Block> const& _body
): ):
CallableDeclaration(_location, _name, _visibility, _parameters, _overrides, _returnParameters), CallableDeclaration(_location, _name, _visibility, _parameters, _isVirtual, _overrides, _returnParameters),
Documented(_documentation), Documented(_documentation),
ImplementationOptional(_body != nullptr), ImplementationOptional(_body != nullptr),
m_stateMutability(_stateMutability), m_stateMutability(_stateMutability),
@ -738,6 +742,7 @@ public:
bool _isStateVar = false, bool _isStateVar = false,
bool _isIndexed = false, bool _isIndexed = false,
bool _isConstant = false, bool _isConstant = false,
bool _isVirtual = false,
ASTPointer<OverrideSpecifier> const& _overrides = nullptr, ASTPointer<OverrideSpecifier> const& _overrides = nullptr,
Location _referenceLocation = Location::Unspecified Location _referenceLocation = Location::Unspecified
): ):
@ -747,9 +752,11 @@ public:
m_isStateVariable(_isStateVar), m_isStateVariable(_isStateVar),
m_isIndexed(_isIndexed), m_isIndexed(_isIndexed),
m_isConstant(_isConstant), m_isConstant(_isConstant),
m_isVirtual(_isVirtual),
m_overrides(_overrides), m_overrides(_overrides),
m_location(_referenceLocation) {} m_location(_referenceLocation) {}
void accept(ASTVisitor& _visitor) override; void accept(ASTVisitor& _visitor) override;
void accept(ASTConstVisitor& _visitor) const override; void accept(ASTConstVisitor& _visitor) const override;
@ -791,6 +798,7 @@ public:
bool isIndexed() const { return m_isIndexed; } bool isIndexed() const { return m_isIndexed; }
bool isConstant() const { return m_isConstant; } bool isConstant() const { return m_isConstant; }
ASTPointer<OverrideSpecifier> const& overrides() const { return m_overrides; } ASTPointer<OverrideSpecifier> const& overrides() const { return m_overrides; }
bool isVirtual() const { return m_isVirtual; }
Location referenceLocation() const { return m_location; } Location referenceLocation() const { return m_location; }
/// @returns a set of allowed storage locations for the variable. /// @returns a set of allowed storage locations for the variable.
std::set<Location> allowedDataLocations() const; std::set<Location> allowedDataLocations() const;
@ -814,6 +822,7 @@ private:
bool m_isStateVariable; ///< Whether or not this is a contract state variable bool m_isStateVariable; ///< Whether or not this is a contract state variable
bool m_isIndexed; ///< Whether this is an indexed variable (used by events). bool m_isIndexed; ///< Whether this is an indexed variable (used by events).
bool m_isConstant; ///< Whether the variable is a compile-time constant. bool m_isConstant; ///< Whether the variable is a compile-time constant.
bool m_isVirtual; ///< Whether the variable is virtual and can be overridden
ASTPointer<OverrideSpecifier> m_overrides; ///< Contains the override specifier node ASTPointer<OverrideSpecifier> m_overrides; ///< Contains the override specifier node
Location m_location; ///< Location of the variable if it is of reference type. Location m_location; ///< Location of the variable if it is of reference type.
}; };
@ -829,10 +838,11 @@ public:
ASTPointer<ASTString> const& _name, ASTPointer<ASTString> const& _name,
ASTPointer<ASTString> const& _documentation, ASTPointer<ASTString> const& _documentation,
ASTPointer<ParameterList> const& _parameters, ASTPointer<ParameterList> const& _parameters,
bool _isVirtual,
ASTPointer<OverrideSpecifier> const& _overrides, ASTPointer<OverrideSpecifier> const& _overrides,
ASTPointer<Block> const& _body ASTPointer<Block> const& _body
): ):
CallableDeclaration(_location, _name, Visibility::Internal, _parameters, _overrides), CallableDeclaration(_location, _name, Visibility::Internal, _parameters, _isVirtual, _overrides),
Documented(_documentation), Documented(_documentation),
m_body(_body) m_body(_body)
{ {

View File

@ -466,6 +466,7 @@ Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(bool _isStateVari
RecursionGuard recursionGuard(*this); RecursionGuard recursionGuard(*this);
FunctionHeaderParserResult result; FunctionHeaderParserResult result;
result.isVirtual = false;
result.overrides = nullptr; result.overrides = nullptr;
VarDeclParserOptions options; VarDeclParserOptions options;
@ -515,6 +516,14 @@ Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(bool _isStateVari
result.overrides = parseOverrideSpecifier(); result.overrides = parseOverrideSpecifier();
} }
else if (!_isStateVariable && token == Token::Virtual)
{
if (result.isVirtual)
parserError("Virtual already specified.");
result.isVirtual = true;
m_scanner->next();
}
else else
break; break;
} }
@ -591,6 +600,7 @@ ASTPointer<ASTNode> Parser::parseFunctionDefinition()
header.visibility, header.visibility,
header.stateMutability, header.stateMutability,
kind, kind,
header.isVirtual,
header.overrides, header.overrides,
docstring, docstring,
header.parameters, header.parameters,
@ -679,6 +689,7 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration(
bool isIndexed = false; bool isIndexed = false;
bool isDeclaredConst = false; bool isDeclaredConst = false;
bool isVirtual = false;
ASTPointer<OverrideSpecifier> overrides = nullptr; ASTPointer<OverrideSpecifier> overrides = nullptr;
Declaration::Visibility visibility(Declaration::Visibility::Default); Declaration::Visibility visibility(Declaration::Visibility::Default);
VariableDeclaration::Location location = VariableDeclaration::Location::Unspecified; VariableDeclaration::Location location = VariableDeclaration::Location::Unspecified;
@ -709,6 +720,14 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration(
overrides = parseOverrideSpecifier(); overrides = parseOverrideSpecifier();
} }
else if (_options.isStateVariable && token == Token::Virtual)
{
if (isVirtual)
parserError("Virtual already specified.");
isVirtual = true;
m_scanner->next();
}
else else
{ {
if (_options.allowIndexed && token == Token::Indexed) if (_options.allowIndexed && token == Token::Indexed)
@ -774,6 +793,7 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration(
_options.isStateVariable, _options.isStateVariable,
isIndexed, isIndexed,
isDeclaredConst, isDeclaredConst,
isVirtual,
overrides, overrides,
location location
); );
@ -804,13 +824,32 @@ ASTPointer<ModifierDefinition> Parser::parseModifierDefinition()
parameters = createEmptyParameterList(); parameters = createEmptyParameterList();
ASTPointer<OverrideSpecifier> overrides; ASTPointer<OverrideSpecifier> overrides;
bool isVirtual = false;
while(true)
{
if (m_scanner->currentToken() == Token::Override)
{
if (overrides)
parserError("Override already specified.");
overrides = parseOverrideSpecifier();
}
else if (m_scanner->currentToken() == Token::Virtual)
{
if (isVirtual)
parserError("Virtual already specified.");
isVirtual = true;
m_scanner->next();
}
else
break;
}
if (m_scanner->currentToken() == Token::Override)
overrides = parseOverrideSpecifier();
ASTPointer<Block> block = parseBlock(); ASTPointer<Block> block = parseBlock();
nodeFactory.setEndPositionFromNode(block); nodeFactory.setEndPositionFromNode(block);
return nodeFactory.createNode<ModifierDefinition>(name, docstring, parameters, overrides, block); return nodeFactory.createNode<ModifierDefinition>(name, docstring, parameters, isVirtual, overrides, block);
} }
ASTPointer<EventDefinition> Parser::parseEventDefinition() ASTPointer<EventDefinition> Parser::parseEventDefinition()

View File

@ -70,6 +70,7 @@ private:
/// This struct is shared for parsing a function header and a function type. /// This struct is shared for parsing a function header and a function type.
struct FunctionHeaderParserResult struct FunctionHeaderParserResult
{ {
bool isVirtual;
ASTPointer<OverrideSpecifier> overrides; ASTPointer<OverrideSpecifier> overrides;
ASTPointer<ParameterList> parameters; ASTPointer<ParameterList> parameters;
ASTPointer<ParameterList> returnParameters; ASTPointer<ParameterList> returnParameters;

View File

@ -118,6 +118,14 @@ while(0)
BOOST_AUTO_TEST_SUITE(SolidityParser) BOOST_AUTO_TEST_SUITE(SolidityParser)
BOOST_AUTO_TEST_CASE(reserved_keywords)
{
BOOST_CHECK(!TokenTraits::isReservedKeyword(Token::Identifier));
BOOST_CHECK(TokenTraits::isReservedKeyword(Token::Abstract));
BOOST_CHECK(TokenTraits::isReservedKeyword(Token::Unchecked));
BOOST_CHECK(!TokenTraits::isReservedKeyword(Token::Illegal));
}
BOOST_AUTO_TEST_CASE(unsatisfied_version) BOOST_AUTO_TEST_CASE(unsatisfied_version)
{ {
char const* text = R"( char const* text = R"(

View File

@ -208,7 +208,7 @@ BOOST_AUTO_TEST_CASE(type_identifiers)
// TypeType is tested with contract // TypeType is tested with contract
auto emptyParams = make_shared<ParameterList>(SourceLocation(), std::vector<ASTPointer<VariableDeclaration>>()); auto emptyParams = make_shared<ParameterList>(SourceLocation(), std::vector<ASTPointer<VariableDeclaration>>());
ModifierDefinition mod(SourceLocation{}, make_shared<string>("modif"), {}, emptyParams, {}, {}); ModifierDefinition mod(SourceLocation{}, make_shared<string>("modif"), {}, emptyParams, {}, {}, {});
BOOST_CHECK_EQUAL(ModifierType(mod).identifier(), "t_modifier$__$"); BOOST_CHECK_EQUAL(ModifierType(mod).identifier(), "t_modifier$__$");
SourceUnit su({}, {}); SourceUnit su({}, {});

View File

@ -0,0 +1,10 @@
contract C
{
function foo() virtual public virtual {}
modifier modi() virtual virtual {_;}
int virtual public virtual variable;
}
// ----
// ParserError: (44-51): Virtual already specified.
// ParserError: (80-87): Virtual already specified.
// ParserError: (113-120): Virtual already specified.

View File

@ -0,0 +1,8 @@
contract C
{
function foo() public virtual {}
function foo2() virtual public {}
modifier modi() virtual {_;}
int public virtual variable;
int virtual public variable2;
}