User-defined operators: Parsing and grammar

This commit is contained in:
wechman 2022-07-06 09:17:59 +02:00 committed by Kamil Śliwak
parent 9a36438441
commit 9445483d60
2 changed files with 47 additions and 2 deletions

View File

@ -311,11 +311,31 @@ errorDefinition:
LParen (parameters+=errorParameter (Comma parameters+=errorParameter)*)? RParen LParen (parameters+=errorParameter (Comma parameters+=errorParameter)*)? RParen
Semicolon; Semicolon;
/**
* Operators that users are allowed to implement for some types with `using for`.
*/
userDefinableOperator:
BitAnd
| BitNot
| BitOr
| BitXor
| Add
| Div
| Mod
| Mul
| Sub
| Equal
| GreaterThan
| GreaterThanOrEqual
| LessThan
| LessThanOrEqual
| NotEqual;
/** /**
* Using directive to attach library functions and free functions to types. * Using directive to attach library functions and free functions to types.
* Can occur within contracts and libraries and at the file level. * Can occur within contracts and libraries and at the file level.
*/ */
usingDirective: Using (identifierPath | (LBrace identifierPath (Comma identifierPath)* RBrace)) For (Mul | typeName) Global? Semicolon; usingDirective: Using (identifierPath | (LBrace identifierPath (As userDefinableOperator)? (Comma identifierPath (As userDefinableOperator)?)* RBrace)) For (Mul | typeName) Global? Semicolon;
/** /**
* A type name can be an elementary type, a function type, a mapping type, a user-defined type * A type name can be an elementary type, a function type, a mapping type, a user-defined type
* (e.g. a contract or struct) or an array type. * (e.g. a contract or struct) or an array type.

View File

@ -23,6 +23,7 @@
#include <libsolidity/parsing/Parser.h> #include <libsolidity/parsing/Parser.h>
#include <libsolidity/ast/UserDefinableOperators.h>
#include <libsolidity/interface/Version.h> #include <libsolidity/interface/Version.h>
#include <libyul/AST.h> #include <libyul/AST.h>
#include <libyul/AsmParser.h> #include <libyul/AsmParser.h>
@ -976,6 +977,7 @@ ASTPointer<UsingForDirective> Parser::parseUsingDirective()
expectToken(Token::Using); expectToken(Token::Using);
vector<ASTPointer<IdentifierPath>> functions; vector<ASTPointer<IdentifierPath>> functions;
vector<optional<Token>> operators;
bool const usesBraces = m_scanner->currentToken() == Token::LBrace; bool const usesBraces = m_scanner->currentToken() == Token::LBrace;
if (usesBraces) if (usesBraces)
{ {
@ -983,12 +985,35 @@ ASTPointer<UsingForDirective> Parser::parseUsingDirective()
{ {
advance(); advance();
functions.emplace_back(parseIdentifierPath()); functions.emplace_back(parseIdentifierPath());
if (m_scanner->currentToken() == Token::As)
{
advance();
Token operator_ = m_scanner->currentToken();
if (!util::contains(userDefinableOperators, operator_))
{
parserError(
4403_error,
fmt::format(
"Not a user-definable operator: {}. Only the following operators can be user-defined: {}",
(!m_scanner->currentLiteral().empty() ? m_scanner->currentLiteral() : string(TokenTraits::toString(operator_))),
util::joinHumanReadable(userDefinableOperators | ranges::views::transform([](Token _t) { return string{TokenTraits::toString(_t)}; }))
)
);
}
operators.emplace_back(operator_);
advance();
}
else
operators.emplace_back(nullopt);
} }
while (m_scanner->currentToken() == Token::Comma); while (m_scanner->currentToken() == Token::Comma);
expectToken(Token::RBrace); expectToken(Token::RBrace);
} }
else else
{
functions.emplace_back(parseIdentifierPath()); functions.emplace_back(parseIdentifierPath());
operators.emplace_back(nullopt);
}
ASTPointer<TypeName> typeName; ASTPointer<TypeName> typeName;
expectToken(Token::For); expectToken(Token::For);
@ -1004,7 +1029,7 @@ ASTPointer<UsingForDirective> Parser::parseUsingDirective()
} }
nodeFactory.markEndPosition(); nodeFactory.markEndPosition();
expectToken(Token::Semicolon); expectToken(Token::Semicolon);
return nodeFactory.createNode<UsingForDirective>(std::move(functions), usesBraces, typeName, global); return nodeFactory.createNode<UsingForDirective>(std::move(functions), std::move(operators), usesBraces, typeName, global);
} }
ASTPointer<ModifierInvocation> Parser::parseModifierInvocation() ASTPointer<ModifierInvocation> Parser::parseModifierInvocation()