mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Parse "virtual" keyword
This commit is contained in:
parent
8569fe7764
commit
7d4e4b6088
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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()
|
||||||
|
@ -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;
|
||||||
|
@ -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"(
|
||||||
|
@ -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({}, {});
|
||||||
|
@ -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.
|
@ -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;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user