mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
User-defined literal suffixes: AST
This commit is contained in:
parent
3b067616de
commit
e06e2c72ce
@ -29,6 +29,7 @@
|
|||||||
#include <libsolidity/ast/TypeProvider.h>
|
#include <libsolidity/ast/TypeProvider.h>
|
||||||
#include <libsolutil/FunctionSelector.h>
|
#include <libsolutil/FunctionSelector.h>
|
||||||
#include <libsolutil/Keccak256.h>
|
#include <libsolutil/Keccak256.h>
|
||||||
|
#include <libsolutil/Visitor.h>
|
||||||
|
|
||||||
#include <range/v3/range/conversion.hpp>
|
#include <range/v3/range/conversion.hpp>
|
||||||
#include <range/v3/view/tail.hpp>
|
#include <range/v3/view/tail.hpp>
|
||||||
@ -986,11 +987,85 @@ IdentifierAnnotation& Identifier::annotation() const
|
|||||||
return initAnnotation<IdentifierAnnotation>();
|
return initAnnotation<IdentifierAnnotation>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Type const& Literal::typeOfValue() const
|
||||||
|
{
|
||||||
|
// no suffix/denomination -> literal is the whole expression and types match.
|
||||||
|
// suffix -> type comes from return value of suffix function.
|
||||||
|
return std::visit(util::GenericVisitor{
|
||||||
|
[](ASTPointer<Identifier> const& _identifier)-> Type const& {
|
||||||
|
solAssert(_identifier->annotation().arguments.has_value());
|
||||||
|
solAssert(_identifier->annotation().arguments->numArguments() == 1);
|
||||||
|
solAssert(_identifier->annotation().arguments->types[0]);
|
||||||
|
return *_identifier->annotation().arguments->types[0];
|
||||||
|
},
|
||||||
|
[](ASTPointer<MemberAccess> const& _memberAccess)-> Type const& {
|
||||||
|
solAssert(_memberAccess->annotation().arguments.has_value());
|
||||||
|
solAssert(_memberAccess->annotation().arguments->numArguments() == 1);
|
||||||
|
solAssert(_memberAccess->annotation().arguments->types[0]);
|
||||||
|
return *_memberAccess->annotation().arguments->types[0];
|
||||||
|
},
|
||||||
|
[&](Literal::SubDenomination) -> Type const& {
|
||||||
|
solAssert(annotation().type);
|
||||||
|
return *annotation().type;
|
||||||
|
},
|
||||||
|
}, m_suffix);
|
||||||
|
}
|
||||||
|
|
||||||
ASTString Literal::valueWithoutUnderscores() const
|
ASTString Literal::valueWithoutUnderscores() const
|
||||||
{
|
{
|
||||||
return boost::erase_all_copy(value(), "_");
|
return boost::erase_all_copy(value(), "_");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Literal::SubDenomination Literal::subDenomination() const
|
||||||
|
{
|
||||||
|
solAssert(holds_alternative<SubDenomination>(m_suffix));
|
||||||
|
return get<SubDenomination>(m_suffix);
|
||||||
|
}
|
||||||
|
|
||||||
|
FunctionDefinition const* Literal::suffixFunction() const
|
||||||
|
{
|
||||||
|
if (holds_alternative<SubDenomination>(m_suffix))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
Declaration const* referencedDeclaration = visit(util::GenericVisitor{
|
||||||
|
[&](ASTPointer<Identifier> const& _identifier) { return _identifier->annotation().referencedDeclaration; },
|
||||||
|
[&](ASTPointer<MemberAccess> const& _memberAccess) { return _memberAccess->annotation().referencedDeclaration; },
|
||||||
|
[&](SubDenomination) -> Declaration const* { solAssert(false); },
|
||||||
|
}, m_suffix);
|
||||||
|
|
||||||
|
solAssert(referencedDeclaration, "Literal suffix must have a definition.");
|
||||||
|
auto const* functionDefinition = dynamic_cast<FunctionDefinition const*>(referencedDeclaration);
|
||||||
|
solAssert(functionDefinition, "Non-denomination literal suffix must be a function.");
|
||||||
|
return functionDefinition;
|
||||||
|
}
|
||||||
|
|
||||||
|
FunctionType const* Literal::suffixFunctionType() const
|
||||||
|
{
|
||||||
|
return dynamic_cast<FunctionType const*>(visit(util::GenericVisitor{
|
||||||
|
[&](ASTPointer<Identifier> const& _identifier) { return _identifier->annotation().type; },
|
||||||
|
[&](ASTPointer<MemberAccess> const& _memberAccess) { return _memberAccess->annotation().type; },
|
||||||
|
[&](Literal::SubDenomination) -> Type const* { return nullptr; },
|
||||||
|
}, suffix()));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Literal::isSuffixed() const
|
||||||
|
{
|
||||||
|
return visit(util::GenericVisitor{
|
||||||
|
[&](ASTPointer<Identifier> const&) { return true; },
|
||||||
|
[&](ASTPointer<MemberAccess> const&) { return true; },
|
||||||
|
[&](Literal::SubDenomination) { return hasSubDenomination(); },
|
||||||
|
}, suffix());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Literal::hasSubDenomination() const
|
||||||
|
{
|
||||||
|
return visit(util::GenericVisitor{
|
||||||
|
[&](ASTPointer<Identifier> const&) { return false; },
|
||||||
|
[&](ASTPointer<MemberAccess> const&) { return false; },
|
||||||
|
[&](Literal::SubDenomination _subDenomination) { return _subDenomination != SubDenomination::None; },
|
||||||
|
}, suffix());
|
||||||
|
}
|
||||||
|
|
||||||
bool Literal::isHexNumber() const
|
bool Literal::isHexNumber() const
|
||||||
{
|
{
|
||||||
if (token() != Token::Number)
|
if (token() != Token::Number)
|
||||||
@ -1000,7 +1075,8 @@ bool Literal::isHexNumber() const
|
|||||||
|
|
||||||
bool Literal::looksLikeAddress() const
|
bool Literal::looksLikeAddress() const
|
||||||
{
|
{
|
||||||
if (subDenomination() != SubDenomination::None)
|
// User suffixes are fine.
|
||||||
|
if (hasSubDenomination())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!isHexNumber())
|
if (!isHexNumber())
|
||||||
|
@ -2377,6 +2377,8 @@ private:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A literal string or number. @see ExpressionCompiler::endVisit() is used to actually parse its value.
|
* A literal string or number. @see ExpressionCompiler::endVisit() is used to actually parse its value.
|
||||||
|
*
|
||||||
|
* It can have a suffix that can lead to a function call.
|
||||||
*/
|
*/
|
||||||
class Literal: public PrimaryExpression
|
class Literal: public PrimaryExpression
|
||||||
{
|
{
|
||||||
@ -2394,24 +2396,41 @@ public:
|
|||||||
Week = static_cast<int>(Token::SubWeek),
|
Week = static_cast<int>(Token::SubWeek),
|
||||||
Year = static_cast<int>(Token::SubYear)
|
Year = static_cast<int>(Token::SubYear)
|
||||||
};
|
};
|
||||||
|
using Suffix = std::variant<SubDenomination, ASTPointer<Identifier>, ASTPointer<MemberAccess>>;
|
||||||
Literal(
|
Literal(
|
||||||
int64_t _id,
|
int64_t _id,
|
||||||
SourceLocation const& _location,
|
SourceLocation const& _location,
|
||||||
Token _token,
|
Token _token,
|
||||||
ASTPointer<ASTString> _value,
|
ASTPointer<ASTString> _value,
|
||||||
SubDenomination _sub = SubDenomination::None
|
Suffix _suffix = SubDenomination::None
|
||||||
):
|
):
|
||||||
PrimaryExpression(_id, _location), m_token(_token), m_value(std::move(_value)), m_subDenomination(_sub) {}
|
PrimaryExpression(_id, _location), m_token(_token), m_value(std::move(_value)), m_suffix(std::move(_suffix)) {}
|
||||||
void accept(ASTVisitor& _visitor) override;
|
void accept(ASTVisitor& _visitor) override;
|
||||||
void accept(ASTConstVisitor& _visitor) const override;
|
void accept(ASTConstVisitor& _visitor) const override;
|
||||||
|
|
||||||
Token token() const { return m_token; }
|
Token token() const { return m_token; }
|
||||||
/// @returns the non-parsed value of the literal
|
/// @returns the non-parsed value of the literal
|
||||||
ASTString const& value() const { return *m_value; }
|
ASTString const& value() const { return *m_value; }
|
||||||
|
Type const& typeOfValue() const;
|
||||||
|
|
||||||
ASTString valueWithoutUnderscores() const;
|
ASTString valueWithoutUnderscores() const;
|
||||||
|
|
||||||
SubDenomination subDenomination() const { return m_subDenomination; }
|
/// @returns The subdenomination represented by the suffix.
|
||||||
|
/// Must not be called if the suffix is not a subdenomination.
|
||||||
|
SubDenomination subDenomination() const;
|
||||||
|
/// @returns The suffix of the literal. Does not check whether the suffix is present or is a
|
||||||
|
/// subdenomination.
|
||||||
|
/// @note Missing suffix is represented by SubDenomination::None.
|
||||||
|
Suffix const& suffix() const { return m_suffix; }
|
||||||
|
/// @returns Function definition associated with the suffix if the suffix is not a subdenomination.
|
||||||
|
/// nullptr otherwise.
|
||||||
|
FunctionDefinition const* suffixFunction() const;
|
||||||
|
FunctionType const* suffixFunctionType() const;
|
||||||
|
|
||||||
|
/// @returns true if the literal is suffixed with either a subdenomination or a suffix function.
|
||||||
|
bool isSuffixed() const;
|
||||||
|
/// @returns true if the literal is suffixed a subdenomination.
|
||||||
|
bool hasSubDenomination() const;
|
||||||
|
|
||||||
/// @returns true if this is a number with a hex prefix.
|
/// @returns true if this is a number with a hex prefix.
|
||||||
bool isHexNumber() const;
|
bool isHexNumber() const;
|
||||||
@ -2426,7 +2445,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
Token m_token;
|
Token m_token;
|
||||||
ASTPointer<ASTString> m_value;
|
ASTPointer<ASTString> m_value;
|
||||||
SubDenomination m_subDenomination;
|
Suffix m_suffix;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
@ -302,6 +302,8 @@ struct IdentifierAnnotation: ExpressionAnnotation
|
|||||||
std::vector<Declaration const*> candidateDeclarations;
|
std::vector<Declaration const*> candidateDeclarations;
|
||||||
/// List of possible declarations it could refer to.
|
/// List of possible declarations it could refer to.
|
||||||
std::vector<Declaration const*> overloadedDeclarations;
|
std::vector<Declaration const*> overloadedDeclarations;
|
||||||
|
/// If the identifier is used as a literal suffix, this points at the literal.
|
||||||
|
Literal const* suffixedLiteral = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MemberAccessAnnotation: ExpressionAnnotation
|
struct MemberAccessAnnotation: ExpressionAnnotation
|
||||||
@ -310,6 +312,8 @@ struct MemberAccessAnnotation: ExpressionAnnotation
|
|||||||
Declaration const* referencedDeclaration = nullptr;
|
Declaration const* referencedDeclaration = nullptr;
|
||||||
/// What kind of lookup needs to be done (static, virtual, super) find the declaration.
|
/// What kind of lookup needs to be done (static, virtual, super) find the declaration.
|
||||||
util::SetOnce<VirtualLookup> requiredLookup;
|
util::SetOnce<VirtualLookup> requiredLookup;
|
||||||
|
/// If the expression is used as a literal suffix, this points at the literal.
|
||||||
|
Literal const* suffixedLiteral = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct OperationAnnotation: ExpressionAnnotation
|
struct OperationAnnotation: ExpressionAnnotation
|
||||||
|
@ -984,17 +984,15 @@ bool ASTJsonExporter::visit(Literal const& _node)
|
|||||||
Json::Value value{_node.value()};
|
Json::Value value{_node.value()};
|
||||||
if (!util::validateUTF8(_node.value()))
|
if (!util::validateUTF8(_node.value()))
|
||||||
value = Json::nullValue;
|
value = Json::nullValue;
|
||||||
Token subdenomination = Token(_node.subDenomination());
|
Json::Value subdenomination = Json::nullValue;
|
||||||
|
// if (auto subden = get_if<Literal::SubDenomination>(&_node.suffix()))
|
||||||
|
// subdenomination = Json::Value{TokenTraits::toString(*subden)};
|
||||||
|
// TODO suffix
|
||||||
std::vector<pair<string, Json::Value>> attributes = {
|
std::vector<pair<string, Json::Value>> attributes = {
|
||||||
make_pair("kind", literalTokenKind(_node.token())),
|
make_pair("kind", literalTokenKind(_node.token())),
|
||||||
make_pair("value", value),
|
make_pair("value", value),
|
||||||
make_pair("hexValue", util::toHex(util::asBytes(_node.value()))),
|
make_pair("hexValue", util::toHex(util::asBytes(_node.value()))),
|
||||||
make_pair(
|
make_pair("subdenomination", subdenomination)
|
||||||
"subdenomination",
|
|
||||||
subdenomination == Token::Illegal ?
|
|
||||||
Json::nullValue :
|
|
||||||
Json::Value{TokenTraits::toString(subdenomination)}
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
appendExpressionAttributes(attributes, _node.annotation());
|
appendExpressionAttributes(attributes, _node.annotation());
|
||||||
setJsonNode(_node, "Literal", std::move(attributes));
|
setJsonNode(_node, "Literal", std::move(attributes));
|
||||||
|
@ -27,6 +27,8 @@
|
|||||||
#include <libsolidity/ast/AST.h>
|
#include <libsolidity/ast/AST.h>
|
||||||
#include <libsolidity/ast/ASTVisitor.h>
|
#include <libsolidity/ast/ASTVisitor.h>
|
||||||
|
|
||||||
|
#include <libsolutil/Visitor.h>
|
||||||
|
|
||||||
namespace solidity::frontend
|
namespace solidity::frontend
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -1014,13 +1016,24 @@ void ElementaryTypeNameExpression::accept(ASTConstVisitor& _visitor) const
|
|||||||
|
|
||||||
void Literal::accept(ASTVisitor& _visitor)
|
void Literal::accept(ASTVisitor& _visitor)
|
||||||
{
|
{
|
||||||
_visitor.visit(*this);
|
if (_visitor.visit(*this))
|
||||||
|
std::visit(solidity::util::GenericVisitor{
|
||||||
|
[&](ASTPointer<Identifier> const& _identifier) { _identifier->accept(_visitor); },
|
||||||
|
[&](ASTPointer<MemberAccess> const& _memberAccess) { _memberAccess->accept(_visitor); },
|
||||||
|
[&](SubDenomination) {},
|
||||||
|
}, m_suffix);
|
||||||
|
|
||||||
_visitor.endVisit(*this);
|
_visitor.endVisit(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Literal::accept(ASTConstVisitor& _visitor) const
|
void Literal::accept(ASTConstVisitor& _visitor) const
|
||||||
{
|
{
|
||||||
_visitor.visit(*this);
|
if (_visitor.visit(*this))
|
||||||
|
std::visit(solidity::util::GenericVisitor{
|
||||||
|
[&](ASTPointer<Identifier> const& _identifier) { _identifier->accept(_visitor); },
|
||||||
|
[&](ASTPointer<MemberAccess> const& _memberAccess) { _memberAccess->accept(_visitor); },
|
||||||
|
[&](SubDenomination) {},
|
||||||
|
}, m_suffix);
|
||||||
_visitor.endVisit(*this);
|
_visitor.endVisit(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user