diff options
author | Lu Guanqun <guanqun.lu@gmail.com> | 2015-01-30 01:26:00 +0800 |
---|---|---|
committer | Lu Guanqun <guanqun.lu@gmail.com> | 2015-01-30 01:32:55 +0800 |
commit | 5c828dc8b25f223f45d85359dbbb5d9e275167c2 (patch) | |
tree | 290d64097f64744341cc147391693ef8c16a9055 | |
parent | 77384af827d7d941620552c4f5f740c3b7c576ef (diff) | |
download | dexon-solidity-5c828dc8b25f223f45d85359dbbb5d9e275167c2.tar dexon-solidity-5c828dc8b25f223f45d85359dbbb5d9e275167c2.tar.gz dexon-solidity-5c828dc8b25f223f45d85359dbbb5d9e275167c2.tar.bz2 dexon-solidity-5c828dc8b25f223f45d85359dbbb5d9e275167c2.tar.lz dexon-solidity-5c828dc8b25f223f45d85359dbbb5d9e275167c2.tar.xz dexon-solidity-5c828dc8b25f223f45d85359dbbb5d9e275167c2.tar.zst dexon-solidity-5c828dc8b25f223f45d85359dbbb5d9e275167c2.zip |
implement named arguments
-rw-r--r-- | AST.cpp | 43 | ||||
-rwxr-xr-x | AST.h | 6 | ||||
-rw-r--r-- | ExpressionCompiler.cpp | 32 | ||||
-rw-r--r-- | Parser.cpp | 45 | ||||
-rw-r--r-- | Parser.h | 3 |
5 files changed, 116 insertions, 13 deletions
@@ -430,6 +430,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(); @@ -442,9 +444,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()) @@ -983,14 +983,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. @@ -999,6 +1000,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 5d44c86f..62066ac6 100644 --- a/ExpressionCompiler.cpp +++ b/ExpressionCompiler.cpp @@ -193,6 +193,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()); @@ -200,8 +201,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()) { @@ -172,7 +172,7 @@ ASTPointer<InheritanceSpecifier> Parser::parseInheritanceSpecifier() if (m_scanner->getCurrentToken() == Token::LPAREN) { m_scanner->next(); - arguments = parseFunctionCallArguments(); + arguments = parseFunctionCallListArguments(); nodeFactory.markEndPosition(); expectToken(Token::RPAREN); } @@ -288,7 +288,7 @@ ASTPointer<ModifierInvocation> Parser::parseModifierInvocation() if (m_scanner->getCurrentToken() == Token::LPAREN) { m_scanner->next(); - arguments = parseFunctionCallArguments(); + arguments = parseFunctionCallListArguments(); nodeFactory.markEndPosition(); expectToken(Token::RPAREN); } @@ -621,10 +621,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: @@ -677,7 +679,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) @@ -692,6 +694,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() { @@ -72,7 +72,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); ///@} ///@{ |