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
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.
* 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
* (e.g. a contract or struct) or an array type.

View File

@ -23,6 +23,7 @@
#include <libsolidity/parsing/Parser.h>
#include <libsolidity/ast/UserDefinableOperators.h>
#include <libsolidity/interface/Version.h>
#include <libyul/AST.h>
#include <libyul/AsmParser.h>
@ -976,6 +977,7 @@ ASTPointer<UsingForDirective> Parser::parseUsingDirective()
expectToken(Token::Using);
vector<ASTPointer<IdentifierPath>> functions;
vector<optional<Token>> operators;
bool const usesBraces = m_scanner->currentToken() == Token::LBrace;
if (usesBraces)
{
@ -983,12 +985,35 @@ ASTPointer<UsingForDirective> Parser::parseUsingDirective()
{
advance();
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);
expectToken(Token::RBrace);
}
else
{
functions.emplace_back(parseIdentifierPath());
operators.emplace_back(nullopt);
}
ASTPointer<TypeName> typeName;
expectToken(Token::For);
@ -1004,7 +1029,7 @@ ASTPointer<UsingForDirective> Parser::parseUsingDirective()
}
nodeFactory.markEndPosition();
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()