mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Parsing function calls.
This commit is contained in:
parent
5d584aded8
commit
49a919b3e0
@ -190,6 +190,10 @@ public:
|
||||
}
|
||||
(*this)(_instr.instruction);
|
||||
}
|
||||
void operator()(assembly::FunctionCall const&)
|
||||
{
|
||||
solAssert(false, "Function call not removed during desugaring phase.");
|
||||
}
|
||||
void operator()(Label const& _label)
|
||||
{
|
||||
m_state.assembly.setSourceLocation(_label.location);
|
||||
|
@ -49,13 +49,15 @@ struct Assignment { SourceLocation location; Identifier variableName; };
|
||||
struct FunctionalAssignment;
|
||||
struct VariableDeclaration;
|
||||
struct FunctionDefinition;
|
||||
struct FunctionCall;
|
||||
struct Block;
|
||||
using Statement = boost::variant<Instruction, Literal, Label, Assignment, Identifier, FunctionalAssignment, FunctionalInstruction, VariableDeclaration, FunctionDefinition, Block>;
|
||||
using Statement = boost::variant<Instruction, Literal, Label, Assignment, Identifier, FunctionalAssignment, FunctionCall, FunctionalInstruction, VariableDeclaration, FunctionDefinition, Block>;
|
||||
/// Functional assignment ("x := mload(20)", expects push-1-expression on the right hand
|
||||
/// side and requires x to occupy exactly one stack slot.
|
||||
struct FunctionalAssignment { SourceLocation location; Identifier variableName; std::shared_ptr<Statement> value; };
|
||||
/// Functional instruction, e.g. "mul(mload(20), add(2, x))"
|
||||
struct FunctionalInstruction { SourceLocation location; Instruction instruction; std::vector<Statement> arguments; };
|
||||
struct FunctionCall { SourceLocation location; Identifier functionName; std::vector<Statement> arguments; };
|
||||
/// Block-scope variable declaration ("let x := mload(20)"), non-hoisted
|
||||
struct VariableDeclaration { SourceLocation location; std::string name; std::shared_ptr<Statement> value; };
|
||||
/// Block that creates a scope (frees declared stack variables)
|
||||
|
@ -257,46 +257,67 @@ assembly::FunctionDefinition Parser::parseFunctionDefinition()
|
||||
return funDef;
|
||||
}
|
||||
|
||||
FunctionalInstruction Parser::parseFunctionalInstruction(assembly::Statement&& _instruction)
|
||||
assembly::Statement Parser::parseFunctionalInstruction(assembly::Statement&& _instruction)
|
||||
{
|
||||
if (_instruction.type() != typeid(Instruction))
|
||||
fatalParserError("Assembly instruction required in front of \"(\")");
|
||||
FunctionalInstruction ret;
|
||||
ret.instruction = std::move(boost::get<Instruction>(_instruction));
|
||||
ret.location = ret.instruction.location;
|
||||
solidity::Instruction instr = ret.instruction.instruction;
|
||||
InstructionInfo instrInfo = instructionInfo(instr);
|
||||
if (solidity::Instruction::DUP1 <= instr && instr <= solidity::Instruction::DUP16)
|
||||
fatalParserError("DUPi instructions not allowed for functional notation");
|
||||
if (solidity::Instruction::SWAP1 <= instr && instr <= solidity::Instruction::SWAP16)
|
||||
fatalParserError("SWAPi instructions not allowed for functional notation");
|
||||
|
||||
expectToken(Token::LParen);
|
||||
unsigned args = unsigned(instrInfo.args);
|
||||
for (unsigned i = 0; i < args; ++i)
|
||||
if (_instruction.type() == typeid(Instruction))
|
||||
{
|
||||
ret.arguments.emplace_back(parseExpression());
|
||||
if (i != args - 1)
|
||||
FunctionalInstruction ret;
|
||||
ret.instruction = std::move(boost::get<Instruction>(_instruction));
|
||||
ret.location = ret.instruction.location;
|
||||
solidity::Instruction instr = ret.instruction.instruction;
|
||||
InstructionInfo instrInfo = instructionInfo(instr);
|
||||
if (solidity::Instruction::DUP1 <= instr && instr <= solidity::Instruction::DUP16)
|
||||
fatalParserError("DUPi instructions not allowed for functional notation");
|
||||
if (solidity::Instruction::SWAP1 <= instr && instr <= solidity::Instruction::SWAP16)
|
||||
fatalParserError("SWAPi instructions not allowed for functional notation");
|
||||
expectToken(Token::LParen);
|
||||
unsigned args = unsigned(instrInfo.args);
|
||||
for (unsigned i = 0; i < args; ++i)
|
||||
{
|
||||
if (m_scanner->currentToken() != Token::Comma)
|
||||
fatalParserError(string(
|
||||
"Expected comma (" +
|
||||
instrInfo.name +
|
||||
" expects " +
|
||||
boost::lexical_cast<string>(args) +
|
||||
" arguments)"
|
||||
));
|
||||
else
|
||||
m_scanner->next();
|
||||
ret.arguments.emplace_back(parseExpression());
|
||||
if (i != args - 1)
|
||||
{
|
||||
if (m_scanner->currentToken() != Token::Comma)
|
||||
fatalParserError(string(
|
||||
"Expected comma (" +
|
||||
instrInfo.name +
|
||||
" expects " +
|
||||
boost::lexical_cast<string>(args) +
|
||||
" arguments)"
|
||||
));
|
||||
else
|
||||
m_scanner->next();
|
||||
}
|
||||
}
|
||||
ret.location.end = endPosition();
|
||||
if (m_scanner->currentToken() == Token::Comma)
|
||||
fatalParserError(
|
||||
string("Expected ')' (" + instrInfo.name + " expects " + boost::lexical_cast<string>(args) + " arguments)")
|
||||
);
|
||||
expectToken(Token::RParen);
|
||||
return ret;
|
||||
}
|
||||
ret.location.end = endPosition();
|
||||
if (m_scanner->currentToken() == Token::Comma)
|
||||
fatalParserError(
|
||||
string("Expected ')' (" + instrInfo.name + " expects " + boost::lexical_cast<string>(args) + " arguments)")
|
||||
);
|
||||
expectToken(Token::RParen);
|
||||
return ret;
|
||||
else if (_instruction.type() == typeid(Identifier))
|
||||
{
|
||||
FunctionCall ret;
|
||||
ret.functionName = std::move(boost::get<Identifier>(_instruction));
|
||||
ret.location = ret.functionName.location;
|
||||
expectToken(Token::LParen);
|
||||
while (m_scanner->currentToken() != Token::RParen)
|
||||
{
|
||||
ret.arguments.emplace_back(parseExpression());
|
||||
if (m_scanner->currentToken() == Token::RParen)
|
||||
break;
|
||||
expectToken(Token::Comma);
|
||||
}
|
||||
ret.location.end = endPosition();
|
||||
expectToken(Token::RParen);
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
fatalParserError("Assembly instruction or function name required in front of \"(\")");
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
string Parser::expectAsmIdentifier()
|
||||
|
@ -68,7 +68,7 @@ protected:
|
||||
Statement parseElementaryOperation(bool _onlySinglePusher = false);
|
||||
VariableDeclaration parseVariableDeclaration();
|
||||
FunctionDefinition parseFunctionDefinition();
|
||||
FunctionalInstruction parseFunctionalInstruction(Statement&& _instruction);
|
||||
Statement parseFunctionalInstruction(Statement&& _instruction);
|
||||
std::string expectAsmIdentifier();
|
||||
};
|
||||
|
||||
|
@ -169,6 +169,11 @@ BOOST_AUTO_TEST_CASE(function_definitions_multiple_args)
|
||||
BOOST_CHECK(successParse("{ function f(a, d) { } function g(a, d) -> (x, y) { } }"));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(function_calls)
|
||||
{
|
||||
BOOST_CHECK(successParse("{ g(1, 2, f(mul(2, 3))) x() }"));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(Printing)
|
||||
|
Loading…
Reference in New Issue
Block a user