Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f18f40a

Browse files
wechmancameel
authored andcommitted
User-defined operators: AST
1 parent fc02cdb commit f18f40a

File tree

7 files changed

+130
-3
lines changed

7 files changed

+130
-3
lines changed

libsolidity/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ set(sources
6363
ast/CallGraph.cpp
6464
ast/CallGraph.h
6565
ast/ExperimentalFeatures.h
66+
ast/UserDefinableOperators.h
6667
ast/Types.cpp
6768
ast/Types.h
6869
ast/TypeProvider.cpp

libsolidity/ast/AST.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@
3030
#include <libsolutil/FunctionSelector.h>
3131
#include <libsolutil/Keccak256.h>
3232

33+
#include <range/v3/range/conversion.hpp>
3334
#include <range/v3/view/tail.hpp>
35+
#include <range/v3/view/zip.hpp>
3436

3537
#include <boost/algorithm/string.hpp>
3638

@@ -367,6 +369,11 @@ TypeDeclarationAnnotation& UserDefinedValueTypeDefinition::annotation() const
367369
return initAnnotation<TypeDeclarationAnnotation>();
368370
}
369371

372+
std::vector<std::pair<ASTPointer<IdentifierPath>, std::optional<Token>>> UsingForDirective::functionsAndOperators() const
373+
{
374+
return ranges::zip_view(m_functionsOrLibrary, m_operators) | ranges::to<vector>;
375+
}
376+
370377
Type const* StructDefinition::type() const
371378
{
372379
solAssert(annotation().recursive.has_value(), "Requested struct type before DeclarationTypeChecker.");
@@ -895,6 +902,37 @@ MemberAccessAnnotation& MemberAccess::annotation() const
895902
return initAnnotation<MemberAccessAnnotation>();
896903
}
897904

905+
OperationAnnotation& UnaryOperation::annotation() const
906+
{
907+
return initAnnotation<OperationAnnotation>();
908+
}
909+
910+
FunctionType const* UnaryOperation::userDefinedFunctionType() const
911+
{
912+
if (*annotation().userDefinedFunction == nullptr)
913+
return nullptr;
914+
915+
FunctionDefinition const* userDefinedFunction = *annotation().userDefinedFunction;
916+
return dynamic_cast<FunctionType const*>(
917+
userDefinedFunction->libraryFunction() ?
918+
userDefinedFunction->typeViaContractName() :
919+
userDefinedFunction->type()
920+
);
921+
}
922+
923+
FunctionType const* BinaryOperation::userDefinedFunctionType() const
924+
{
925+
if (*annotation().userDefinedFunction == nullptr)
926+
return nullptr;
927+
928+
FunctionDefinition const* userDefinedFunction = *annotation().userDefinedFunction;
929+
return dynamic_cast<FunctionType const*>(
930+
userDefinedFunction->libraryFunction() ?
931+
userDefinedFunction->typeViaContractName() :
932+
userDefinedFunction->type()
933+
);
934+
}
935+
898936
BinaryOperationAnnotation& BinaryOperation::annotation() const
899937
{
900938
return initAnnotation<BinaryOperationAnnotation>();

libsolidity/ast/AST.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -663,16 +663,19 @@ class UsingForDirective: public ASTNode
663663
int64_t _id,
664664
SourceLocation const& _location,
665665
std::vector<ASTPointer<IdentifierPath>> _functionsOrLibrary,
666+
std::vector<std::optional<Token>> _operators,
666667
bool _usesBraces,
667668
ASTPointer<TypeName> _typeName,
668669
bool _global
669670
):
670671
ASTNode(_id, _location),
671672
m_functionsOrLibrary(std::move(_functionsOrLibrary)),
673+
m_operators(std::move(_operators)),
672674
m_usesBraces(_usesBraces),
673675
m_typeName(std::move(_typeName)),
674676
m_global{_global}
675677
{
678+
solAssert(m_functionsOrLibrary.size() == m_operators.size());
676679
}
677680

678681
void accept(ASTVisitor& _visitor) override;
@@ -683,12 +686,18 @@ class UsingForDirective: public ASTNode
683686

684687
/// @returns a list of functions or the single library.
685688
std::vector<ASTPointer<IdentifierPath>> const& functionsOrLibrary() const { return m_functionsOrLibrary; }
689+
std::vector<std::pair<ASTPointer<IdentifierPath>, std::optional<Token>>> functionsAndOperators() const;
686690
bool usesBraces() const { return m_usesBraces; }
687691
bool global() const { return m_global; }
688692

689693
private:
690694
/// Either the single library or a list of functions.
691695
std::vector<ASTPointer<IdentifierPath>> m_functionsOrLibrary;
696+
/// Operators, the functions from @a m_functionsOrLibrary implement.
697+
/// A token if the corresponding element in m_functionsOrLibrary
698+
/// defines an operator, nullptr otherwise.
699+
/// Note that this vector size must be equal to m_functionsOrLibrary size.
700+
std::vector<std::optional<Token>> m_operators;
692701
bool m_usesBraces;
693702
ASTPointer<TypeName> m_typeName;
694703
bool m_global = false;
@@ -2073,6 +2082,10 @@ class UnaryOperation: public Expression
20732082
bool isPrefixOperation() const { return m_isPrefix; }
20742083
Expression const& subExpression() const { return *m_subExpression; }
20752084

2085+
FunctionType const* userDefinedFunctionType() const;
2086+
2087+
OperationAnnotation& annotation() const override;
2088+
20762089
private:
20772090
Token m_operator;
20782091
ASTPointer<Expression> m_subExpression;
@@ -2104,6 +2117,8 @@ class BinaryOperation: public Expression
21042117
Expression const& rightExpression() const { return *m_right; }
21052118
Token getOperator() const { return m_operator; }
21062119

2120+
FunctionType const* userDefinedFunctionType() const;
2121+
21072122
BinaryOperationAnnotation& annotation() const override;
21082123

21092124
private:

libsolidity/ast/ASTAnnotations.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,12 @@ struct MemberAccessAnnotation: ExpressionAnnotation
312312
util::SetOnce<VirtualLookup> requiredLookup;
313313
};
314314

315-
struct BinaryOperationAnnotation: ExpressionAnnotation
315+
struct OperationAnnotation: ExpressionAnnotation
316+
{
317+
util::SetOnce<FunctionDefinition const*> userDefinedFunction;
318+
};
319+
320+
struct BinaryOperationAnnotation: OperationAnnotation
316321
{
317322
/// The common type that is used for the operation, not necessarily the result type (which
318323
/// e.g. for comparisons is bool).

libsolidity/ast/ASTJsonExporter.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -329,19 +329,27 @@ bool ASTJsonExporter::visit(UsingForDirective const& _node)
329329
vector<pair<string, Json::Value>> attributes = {
330330
make_pair("typeName", _node.typeName() ? toJson(*_node.typeName()) : Json::nullValue)
331331
};
332+
332333
if (_node.usesBraces())
333334
{
334335
Json::Value functionList;
335-
for (auto const& function: _node.functionsOrLibrary())
336+
for (auto&& [function, op]: _node.functionsAndOperators())
336337
{
337338
Json::Value functionNode;
338339
functionNode["function"] = toJson(*function);
340+
if (op.has_value())
341+
functionNode["operator"] = string(TokenTraits::toString(*op));
339342
functionList.append(std::move(functionNode));
340343
}
341344
attributes.emplace_back("functionList", std::move(functionList));
342345
}
343346
else
344-
attributes.emplace_back("libraryName", toJson(*_node.functionsOrLibrary().front()));
347+
{
348+
auto const& functionAndOperators = _node.functionsAndOperators();
349+
solAssert(_node.functionsAndOperators().size() == 1);
350+
solAssert(!functionAndOperators.front().second.has_value());
351+
attributes.emplace_back("libraryName", toJson(*(functionAndOperators.front().first)));
352+
}
345353
attributes.emplace_back("global", _node.global());
346354

347355
setJsonNode(_node, "UsingForDirective", std::move(attributes));
@@ -829,6 +837,9 @@ bool ASTJsonExporter::visit(UnaryOperation const& _node)
829837
make_pair("operator", TokenTraits::toString(_node.getOperator())),
830838
make_pair("subExpression", toJson(_node.subExpression()))
831839
};
840+
// NOTE: This annotation is guaranteed to be set but only if we didn't stop at the parsing stage.
841+
if (_node.annotation().userDefinedFunction.set() && *_node.annotation().userDefinedFunction != nullptr)
842+
attributes.emplace_back("function", nodeId(**_node.annotation().userDefinedFunction));
832843
appendExpressionAttributes(attributes, _node.annotation());
833844
setJsonNode(_node, "UnaryOperation", std::move(attributes));
834845
return false;
@@ -842,6 +853,9 @@ bool ASTJsonExporter::visit(BinaryOperation const& _node)
842853
make_pair("rightExpression", toJson(_node.rightExpression())),
843854
make_pair("commonType", typePointerToJson(_node.annotation().commonType)),
844855
};
856+
// NOTE: This annotation is guaranteed to be set but only if we didn't stop at the parsing stage.
857+
if (_node.annotation().userDefinedFunction.set() && *_node.annotation().userDefinedFunction != nullptr)
858+
attributes.emplace_back("function", nodeId(**_node.annotation().userDefinedFunction));
845859
appendExpressionAttributes(attributes, _node.annotation());
846860
setJsonNode(_node, "BinaryOperation", std::move(attributes));
847861
return false;

libsolidity/ast/ASTJsonImporter.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
*/
2323

2424
#include <libsolidity/ast/ASTJsonImporter.h>
25+
#include <libsolidity/ast/UserDefinableOperators.h>
2526

2627
#include <libyul/AsmJsonImporter.h>
2728
#include <libyul/AST.h>
@@ -397,15 +398,32 @@ ASTPointer<InheritanceSpecifier> ASTJsonImporter::createInheritanceSpecifier(Jso
397398
ASTPointer<UsingForDirective> ASTJsonImporter::createUsingForDirective(Json::Value const& _node)
398399
{
399400
vector<ASTPointer<IdentifierPath>> functions;
401+
vector<optional<Token>> operators;
400402
if (_node.isMember("libraryName"))
403+
{
404+
astAssert(!_node["libraryName"].isArray());
405+
astAssert(!_node["libraryName"]["operator"]);
401406
functions.emplace_back(createIdentifierPath(_node["libraryName"]));
407+
operators.emplace_back(nullopt);
408+
}
402409
else if (_node.isMember("functionList"))
403410
for (Json::Value const& function: _node["functionList"])
411+
{
404412
functions.emplace_back(createIdentifierPath(function["function"]));
413+
if (function.isMember("operator"))
414+
{
415+
Token const token = scanSingleToken(function["operator"]);
416+
astAssert(util::contains(frontend::userDefinableOperators, token));
417+
operators.emplace_back(token);
418+
}
419+
else
420+
operators.emplace_back(nullopt);
421+
}
405422

406423
return createASTNode<UsingForDirective>(
407424
_node,
408425
std::move(functions),
426+
std::move(operators),
409427
!_node.isMember("libraryName"),
410428
_node["typeName"].isNull() ? nullptr : convertJsonToASTNode<TypeName>(_node["typeName"]),
411429
memberAsBool(_node, "global")
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#pragma once
2+
3+
#include <liblangutil/Token.h>
4+
5+
#include <vector>
6+
7+
namespace solidity::frontend
8+
{
9+
10+
std::vector<langutil::Token> const userDefinableOperators = {
11+
// Bitwise
12+
langutil::Token::BitOr,
13+
langutil::Token::BitAnd,
14+
langutil::Token::BitXor,
15+
langutil::Token::BitNot,
16+
langutil::Token::SHL,
17+
langutil::Token::SAR,
18+
// Arithmetic
19+
langutil::Token::Add,
20+
langutil::Token::Sub,
21+
langutil::Token::Mul,
22+
langutil::Token::Div,
23+
langutil::Token::Mod,
24+
langutil::Token::Exp,
25+
// Comparison
26+
langutil::Token::Equal,
27+
langutil::Token::NotEqual,
28+
langutil::Token::LessThan,
29+
langutil::Token::GreaterThan,
30+
langutil::Token::LessThanOrEqual,
31+
langutil::Token::GreaterThanOrEqual,
32+
// Boolean
33+
langutil::Token::Not
34+
};
35+
36+
}

0 commit comments

Comments
 (0)