mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
implement named arguments
This commit is contained in:
parent
77384af827
commit
5c828dc8b2
37
AST.cpp
37
AST.cpp
@ -430,6 +430,8 @@ void FunctionCall::checkTypeRequirements()
|
|||||||
// number of non-mapping members
|
// number of non-mapping members
|
||||||
if (m_arguments.size() != 1)
|
if (m_arguments.size() != 1)
|
||||||
BOOST_THROW_EXCEPTION(createTypeError("More than one argument for explicit type conversion."));
|
BOOST_THROW_EXCEPTION(createTypeError("More than one argument for explicit type conversion."));
|
||||||
|
if (!m_names.empty())
|
||||||
|
BOOST_THROW_EXCEPTION(createTypeError("Type conversion can't allow named arguments."));
|
||||||
if (!m_arguments.front()->getType()->isExplicitlyConvertibleTo(*type.getActualType()))
|
if (!m_arguments.front()->getType()->isExplicitlyConvertibleTo(*type.getActualType()))
|
||||||
BOOST_THROW_EXCEPTION(createTypeError("Explicit type conversion not allowed."));
|
BOOST_THROW_EXCEPTION(createTypeError("Explicit type conversion not allowed."));
|
||||||
m_type = type.getActualType();
|
m_type = type.getActualType();
|
||||||
@ -442,9 +444,44 @@ void FunctionCall::checkTypeRequirements()
|
|||||||
TypePointers const& parameterTypes = functionType->getParameterTypes();
|
TypePointers const& parameterTypes = functionType->getParameterTypes();
|
||||||
if (parameterTypes.size() != m_arguments.size())
|
if (parameterTypes.size() != m_arguments.size())
|
||||||
BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for function call."));
|
BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for function call."));
|
||||||
|
|
||||||
|
if (m_names.empty())
|
||||||
|
{
|
||||||
for (size_t i = 0; i < m_arguments.size(); ++i)
|
for (size_t i = 0; i < m_arguments.size(); ++i)
|
||||||
if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[i]))
|
if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[i]))
|
||||||
BOOST_THROW_EXCEPTION(createTypeError("Invalid type for argument in function call."));
|
BOOST_THROW_EXCEPTION(createTypeError("Invalid type for argument in function call."));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto const& parameterNames = functionType->getParameterNames();
|
||||||
|
if (parameterNames.size() != m_names.size())
|
||||||
|
BOOST_THROW_EXCEPTION(createTypeError("Some argument names are missing."));
|
||||||
|
|
||||||
|
// check duplicate names
|
||||||
|
for (size_t i = 0; i < m_names.size(); i++) {
|
||||||
|
for (size_t j = i + 1; j < m_names.size(); j++) {
|
||||||
|
if (m_names[i] == m_names[j])
|
||||||
|
BOOST_THROW_EXCEPTION(createTypeError("Duplicate named argument."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < m_names.size(); i++) {
|
||||||
|
bool found = false;
|
||||||
|
for (size_t j = 0; j < parameterNames.size(); j++) {
|
||||||
|
if (parameterNames[j] == m_names[i]) {
|
||||||
|
// check type convertible
|
||||||
|
if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[j]))
|
||||||
|
BOOST_THROW_EXCEPTION(createTypeError("Invalid type for argument in function call."));
|
||||||
|
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found)
|
||||||
|
BOOST_THROW_EXCEPTION(createTypeError("Named argument doesn't match function declaration."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// @todo actually the return type should be an anonymous struct,
|
// @todo actually the return type should be an anonymous struct,
|
||||||
// but we change it to the type of the first return value until we have structs
|
// but we change it to the type of the first return value until we have structs
|
||||||
if (functionType->getReturnParameterTypes().empty())
|
if (functionType->getReturnParameterTypes().empty())
|
||||||
|
6
AST.h
6
AST.h
@ -983,14 +983,15 @@ class FunctionCall: public Expression
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FunctionCall(Location const& _location, ASTPointer<Expression> const& _expression,
|
FunctionCall(Location const& _location, ASTPointer<Expression> const& _expression,
|
||||||
std::vector<ASTPointer<Expression>> const& _arguments):
|
std::vector<ASTPointer<Expression>> const& _arguments, std::vector<std::string> const& _names):
|
||||||
Expression(_location), m_expression(_expression), m_arguments(_arguments) {}
|
Expression(_location), m_expression(_expression), m_arguments(_arguments), m_names(_names) {}
|
||||||
virtual void accept(ASTVisitor& _visitor) override;
|
virtual void accept(ASTVisitor& _visitor) override;
|
||||||
virtual void accept(ASTConstVisitor& _visitor) const override;
|
virtual void accept(ASTConstVisitor& _visitor) const override;
|
||||||
virtual void checkTypeRequirements() override;
|
virtual void checkTypeRequirements() override;
|
||||||
|
|
||||||
Expression const& getExpression() const { return *m_expression; }
|
Expression const& getExpression() const { return *m_expression; }
|
||||||
std::vector<ASTPointer<Expression const>> getArguments() const { return {m_arguments.begin(), m_arguments.end()}; }
|
std::vector<ASTPointer<Expression const>> getArguments() const { return {m_arguments.begin(), m_arguments.end()}; }
|
||||||
|
std::vector<std::string> const& getNames() const { return m_names; }
|
||||||
|
|
||||||
/// Returns true if this is not an actual function call, but an explicit type conversion
|
/// Returns true if this is not an actual function call, but an explicit type conversion
|
||||||
/// or constructor call.
|
/// or constructor call.
|
||||||
@ -999,6 +1000,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
ASTPointer<Expression> m_expression;
|
ASTPointer<Expression> m_expression;
|
||||||
std::vector<ASTPointer<Expression>> m_arguments;
|
std::vector<ASTPointer<Expression>> m_arguments;
|
||||||
|
std::vector<std::string> m_names;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -193,6 +193,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
{
|
{
|
||||||
//@todo struct construction
|
//@todo struct construction
|
||||||
solAssert(_functionCall.getArguments().size() == 1, "");
|
solAssert(_functionCall.getArguments().size() == 1, "");
|
||||||
|
solAssert(_functionCall.getNames().empty(), "");
|
||||||
Expression const& firstArgument = *_functionCall.getArguments().front();
|
Expression const& firstArgument = *_functionCall.getArguments().front();
|
||||||
firstArgument.accept(*this);
|
firstArgument.accept(*this);
|
||||||
appendTypeConversion(*firstArgument.getType(), *_functionCall.getType());
|
appendTypeConversion(*firstArgument.getType(), *_functionCall.getType());
|
||||||
@ -200,8 +201,35 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
FunctionType const& function = dynamic_cast<FunctionType const&>(*_functionCall.getExpression().getType());
|
FunctionType const& function = dynamic_cast<FunctionType const&>(*_functionCall.getExpression().getType());
|
||||||
vector<ASTPointer<Expression const>> arguments = _functionCall.getArguments();
|
TypePointers const& parameterTypes = function.getParameterTypes();
|
||||||
solAssert(arguments.size() == function.getParameterTypes().size(), "");
|
vector<string> const& parameterNames = function.getParameterNames();
|
||||||
|
vector<ASTPointer<Expression const>> const& callArguments = _functionCall.getArguments();
|
||||||
|
vector<string> const& callArgumentNames = _functionCall.getNames();
|
||||||
|
solAssert(callArguments.size() == parameterTypes.size(), "");
|
||||||
|
|
||||||
|
vector<ASTPointer<Expression const>> arguments;
|
||||||
|
if (callArgumentNames.empty())
|
||||||
|
{
|
||||||
|
// normal arguments
|
||||||
|
arguments = {callArguments.begin(), callArguments.end()};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// named arguments
|
||||||
|
for (size_t i = 0; i < parameterNames.size(); i++) {
|
||||||
|
bool found = false;
|
||||||
|
for (size_t j = 0; j < callArgumentNames.size(); j++) {
|
||||||
|
if (parameterNames[i] == callArgumentNames[j]) {
|
||||||
|
// we found the actual parameter position
|
||||||
|
arguments.push_back(callArguments[j]);
|
||||||
|
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
solAssert(found, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch (function.getLocation())
|
switch (function.getLocation())
|
||||||
{
|
{
|
||||||
|
45
Parser.cpp
45
Parser.cpp
@ -172,7 +172,7 @@ ASTPointer<InheritanceSpecifier> Parser::parseInheritanceSpecifier()
|
|||||||
if (m_scanner->getCurrentToken() == Token::LPAREN)
|
if (m_scanner->getCurrentToken() == Token::LPAREN)
|
||||||
{
|
{
|
||||||
m_scanner->next();
|
m_scanner->next();
|
||||||
arguments = parseFunctionCallArguments();
|
arguments = parseFunctionCallListArguments();
|
||||||
nodeFactory.markEndPosition();
|
nodeFactory.markEndPosition();
|
||||||
expectToken(Token::RPAREN);
|
expectToken(Token::RPAREN);
|
||||||
}
|
}
|
||||||
@ -288,7 +288,7 @@ ASTPointer<ModifierInvocation> Parser::parseModifierInvocation()
|
|||||||
if (m_scanner->getCurrentToken() == Token::LPAREN)
|
if (m_scanner->getCurrentToken() == Token::LPAREN)
|
||||||
{
|
{
|
||||||
m_scanner->next();
|
m_scanner->next();
|
||||||
arguments = parseFunctionCallArguments();
|
arguments = parseFunctionCallListArguments();
|
||||||
nodeFactory.markEndPosition();
|
nodeFactory.markEndPosition();
|
||||||
expectToken(Token::RPAREN);
|
expectToken(Token::RPAREN);
|
||||||
}
|
}
|
||||||
@ -621,10 +621,12 @@ ASTPointer<Expression> Parser::parseLeftHandSideExpression()
|
|||||||
case Token::LPAREN:
|
case Token::LPAREN:
|
||||||
{
|
{
|
||||||
m_scanner->next();
|
m_scanner->next();
|
||||||
vector<ASTPointer<Expression>> arguments = parseFunctionCallArguments();
|
vector<ASTPointer<Expression>> arguments;
|
||||||
|
vector<string> names;
|
||||||
|
parseFunctionCallArguments(arguments, names);
|
||||||
nodeFactory.markEndPosition();
|
nodeFactory.markEndPosition();
|
||||||
expectToken(Token::RPAREN);
|
expectToken(Token::RPAREN);
|
||||||
expression = nodeFactory.createNode<FunctionCall>(expression, arguments);
|
expression = nodeFactory.createNode<FunctionCall>(expression, arguments, names);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -677,7 +679,7 @@ ASTPointer<Expression> Parser::parsePrimaryExpression()
|
|||||||
return expression;
|
return expression;
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<ASTPointer<Expression>> Parser::parseFunctionCallArguments()
|
vector<ASTPointer<Expression>> Parser::parseFunctionCallListArguments()
|
||||||
{
|
{
|
||||||
vector<ASTPointer<Expression>> arguments;
|
vector<ASTPointer<Expression>> arguments;
|
||||||
if (m_scanner->getCurrentToken() != Token::RPAREN)
|
if (m_scanner->getCurrentToken() != Token::RPAREN)
|
||||||
@ -692,6 +694,39 @@ vector<ASTPointer<Expression>> Parser::parseFunctionCallArguments()
|
|||||||
return arguments;
|
return arguments;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Parser::parseFunctionCallArguments(vector<ASTPointer<Expression>>& _arguments, vector<string>& _names)
|
||||||
|
{
|
||||||
|
Token::Value token = m_scanner->getCurrentToken();
|
||||||
|
if (token == Token::LBRACE)
|
||||||
|
{
|
||||||
|
// call({arg1 : 1, arg2 : 2 })
|
||||||
|
expectToken(Token::LBRACE);
|
||||||
|
while (m_scanner->getCurrentToken() != Token::RBRACE)
|
||||||
|
{
|
||||||
|
string identifier = *expectIdentifierToken();
|
||||||
|
expectToken(Token::COLON);
|
||||||
|
ASTPointer<Expression> expression = parseExpression();
|
||||||
|
|
||||||
|
_arguments.push_back(expression);
|
||||||
|
_names.push_back(identifier);
|
||||||
|
|
||||||
|
if (m_scanner->getCurrentToken() == Token::COMMA)
|
||||||
|
{
|
||||||
|
expectToken(Token::COMMA);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expectToken(Token::RBRACE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_arguments = parseFunctionCallListArguments();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Parser::peekVariableDefinition()
|
bool Parser::peekVariableDefinition()
|
||||||
{
|
{
|
||||||
|
3
Parser.h
3
Parser.h
@ -72,7 +72,8 @@ private:
|
|||||||
ASTPointer<Expression> parseUnaryExpression();
|
ASTPointer<Expression> parseUnaryExpression();
|
||||||
ASTPointer<Expression> parseLeftHandSideExpression();
|
ASTPointer<Expression> parseLeftHandSideExpression();
|
||||||
ASTPointer<Expression> parsePrimaryExpression();
|
ASTPointer<Expression> parsePrimaryExpression();
|
||||||
std::vector<ASTPointer<Expression>> parseFunctionCallArguments();
|
std::vector<ASTPointer<Expression>> parseFunctionCallListArguments();
|
||||||
|
void parseFunctionCallArguments(std::vector<ASTPointer<Expression>> & _arguments, std::vector<std::string> & _names);
|
||||||
///@}
|
///@}
|
||||||
|
|
||||||
///@{
|
///@{
|
||||||
|
Loading…
Reference in New Issue
Block a user