aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AST.cpp43
-rwxr-xr-xAST.h6
-rw-r--r--ExpressionCompiler.cpp32
-rw-r--r--Parser.cpp45
-rw-r--r--Parser.h3
5 files changed, 116 insertions, 13 deletions
diff --git a/AST.cpp b/AST.cpp
index b07959b3..33cb4ac3 100644
--- a/AST.cpp
+++ b/AST.cpp
@@ -475,6 +475,8 @@ void FunctionCall::checkTypeRequirements()
// number of non-mapping members
if (m_arguments.size() != 1)
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()))
BOOST_THROW_EXCEPTION(createTypeError("Explicit type conversion not allowed."));
m_type = type.getActualType();
@@ -487,9 +489,44 @@ void FunctionCall::checkTypeRequirements()
TypePointers const& parameterTypes = functionType->getParameterTypes();
if (parameterTypes.size() != m_arguments.size())
BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for function call."));
- for (size_t i = 0; i < m_arguments.size(); ++i)
- if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[i]))
- BOOST_THROW_EXCEPTION(createTypeError("Invalid type for argument in function call."));
+
+ if (m_names.empty())
+ {
+ for (size_t i = 0; i < m_arguments.size(); ++i)
+ if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[i]))
+ 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,
// but we change it to the type of the first return value until we have structs
if (functionType->getReturnParameterTypes().empty())
diff --git a/AST.h b/AST.h
index 8e8641c7..bd153513 100755
--- a/AST.h
+++ b/AST.h
@@ -963,14 +963,15 @@ class FunctionCall: public Expression
{
public:
FunctionCall(Location const& _location, ASTPointer<Expression> const& _expression,
- std::vector<ASTPointer<Expression>> const& _arguments):
- Expression(_location), m_expression(_expression), m_arguments(_arguments) {}
+ std::vector<ASTPointer<Expression>> const& _arguments, std::vector<std::string> const& _names):
+ Expression(_location), m_expression(_expression), m_arguments(_arguments), m_names(_names) {}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
virtual void checkTypeRequirements() override;
Expression const& getExpression() const { return *m_expression; }
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
/// or constructor call.
@@ -979,6 +980,7 @@ public:
private:
ASTPointer<Expression> m_expression;
std::vector<ASTPointer<Expression>> m_arguments;
+ std::vector<std::string> m_names;
};
/**
diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp
index 45e0e80b..13d8ccf1 100644
--- a/ExpressionCompiler.cpp
+++ b/ExpressionCompiler.cpp
@@ -195,6 +195,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
{
//@todo struct construction
solAssert(_functionCall.getArguments().size() == 1, "");
+ solAssert(_functionCall.getNames().empty(), "");
Expression const& firstArgument = *_functionCall.getArguments().front();
firstArgument.accept(*this);
appendTypeConversion(*firstArgument.getType(), *_functionCall.getType());
@@ -202,8 +203,35 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
else
{
FunctionType const& function = dynamic_cast<FunctionType const&>(*_functionCall.getExpression().getType());
- vector<ASTPointer<Expression const>> arguments = _functionCall.getArguments();
- solAssert(arguments.size() == function.getParameterTypes().size(), "");
+ TypePointers const& parameterTypes = function.getParameterTypes();
+ 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())
{
diff --git a/Parser.cpp b/Parser.cpp
index cc75fc0a..1cf0bce5 100644
--- a/Parser.cpp
+++ b/Parser.cpp
@@ -169,7 +169,7 @@ ASTPointer<InheritanceSpecifier> Parser::parseInheritanceSpecifier()
if (m_scanner->getCurrentToken() == Token::LPAREN)
{
m_scanner->next();
- arguments = parseFunctionCallArguments();
+ arguments = parseFunctionCallListArguments();
nodeFactory.markEndPosition();
expectToken(Token::RPAREN);
}
@@ -332,7 +332,7 @@ ASTPointer<ModifierInvocation> Parser::parseModifierInvocation()
if (m_scanner->getCurrentToken() == Token::LPAREN)
{
m_scanner->next();
- arguments = parseFunctionCallArguments();
+ arguments = parseFunctionCallListArguments();
nodeFactory.markEndPosition();
expectToken(Token::RPAREN);
}
@@ -667,10 +667,12 @@ ASTPointer<Expression> Parser::parseLeftHandSideExpression()
case Token::LPAREN:
{
m_scanner->next();
- vector<ASTPointer<Expression>> arguments = parseFunctionCallArguments();
+ vector<ASTPointer<Expression>> arguments;
+ vector<string> names;
+ parseFunctionCallArguments(arguments, names);
nodeFactory.markEndPosition();
expectToken(Token::RPAREN);
- expression = nodeFactory.createNode<FunctionCall>(expression, arguments);
+ expression = nodeFactory.createNode<FunctionCall>(expression, arguments, names);
}
break;
default:
@@ -723,7 +725,7 @@ ASTPointer<Expression> Parser::parsePrimaryExpression()
return expression;
}
-vector<ASTPointer<Expression>> Parser::parseFunctionCallArguments()
+vector<ASTPointer<Expression>> Parser::parseFunctionCallListArguments()
{
vector<ASTPointer<Expression>> arguments;
if (m_scanner->getCurrentToken() != Token::RPAREN)
@@ -738,6 +740,39 @@ vector<ASTPointer<Expression>> Parser::parseFunctionCallArguments()
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()
{
diff --git a/Parser.h b/Parser.h
index 388fd7a9..e8d521c9 100644
--- a/Parser.h
+++ b/Parser.h
@@ -81,7 +81,8 @@ private:
ASTPointer<Expression> parseUnaryExpression();
ASTPointer<Expression> parseLeftHandSideExpression();
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);
///@}
///@{