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);
|
(*this)(_instr.instruction);
|
||||||
}
|
}
|
||||||
|
void operator()(assembly::FunctionCall const&)
|
||||||
|
{
|
||||||
|
solAssert(false, "Function call not removed during desugaring phase.");
|
||||||
|
}
|
||||||
void operator()(Label const& _label)
|
void operator()(Label const& _label)
|
||||||
{
|
{
|
||||||
m_state.assembly.setSourceLocation(_label.location);
|
m_state.assembly.setSourceLocation(_label.location);
|
||||||
|
@ -49,13 +49,15 @@ struct Assignment { SourceLocation location; Identifier variableName; };
|
|||||||
struct FunctionalAssignment;
|
struct FunctionalAssignment;
|
||||||
struct VariableDeclaration;
|
struct VariableDeclaration;
|
||||||
struct FunctionDefinition;
|
struct FunctionDefinition;
|
||||||
|
struct FunctionCall;
|
||||||
struct Block;
|
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
|
/// Functional assignment ("x := mload(20)", expects push-1-expression on the right hand
|
||||||
/// side and requires x to occupy exactly one stack slot.
|
/// side and requires x to occupy exactly one stack slot.
|
||||||
struct FunctionalAssignment { SourceLocation location; Identifier variableName; std::shared_ptr<Statement> value; };
|
struct FunctionalAssignment { SourceLocation location; Identifier variableName; std::shared_ptr<Statement> value; };
|
||||||
/// Functional instruction, e.g. "mul(mload(20), add(2, x))"
|
/// Functional instruction, e.g. "mul(mload(20), add(2, x))"
|
||||||
struct FunctionalInstruction { SourceLocation location; Instruction instruction; std::vector<Statement> arguments; };
|
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
|
/// Block-scope variable declaration ("let x := mload(20)"), non-hoisted
|
||||||
struct VariableDeclaration { SourceLocation location; std::string name; std::shared_ptr<Statement> value; };
|
struct VariableDeclaration { SourceLocation location; std::string name; std::shared_ptr<Statement> value; };
|
||||||
/// Block that creates a scope (frees declared stack variables)
|
/// Block that creates a scope (frees declared stack variables)
|
||||||
|
@ -257,46 +257,67 @@ assembly::FunctionDefinition Parser::parseFunctionDefinition()
|
|||||||
return funDef;
|
return funDef;
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionalInstruction Parser::parseFunctionalInstruction(assembly::Statement&& _instruction)
|
assembly::Statement Parser::parseFunctionalInstruction(assembly::Statement&& _instruction)
|
||||||
{
|
{
|
||||||
if (_instruction.type() != typeid(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)
|
|
||||||
{
|
{
|
||||||
ret.arguments.emplace_back(parseExpression());
|
FunctionalInstruction ret;
|
||||||
if (i != args - 1)
|
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)
|
ret.arguments.emplace_back(parseExpression());
|
||||||
fatalParserError(string(
|
if (i != args - 1)
|
||||||
"Expected comma (" +
|
{
|
||||||
instrInfo.name +
|
if (m_scanner->currentToken() != Token::Comma)
|
||||||
" expects " +
|
fatalParserError(string(
|
||||||
boost::lexical_cast<string>(args) +
|
"Expected comma (" +
|
||||||
" arguments)"
|
instrInfo.name +
|
||||||
));
|
" expects " +
|
||||||
else
|
boost::lexical_cast<string>(args) +
|
||||||
m_scanner->next();
|
" 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();
|
else if (_instruction.type() == typeid(Identifier))
|
||||||
if (m_scanner->currentToken() == Token::Comma)
|
{
|
||||||
fatalParserError(
|
FunctionCall ret;
|
||||||
string("Expected ')' (" + instrInfo.name + " expects " + boost::lexical_cast<string>(args) + " arguments)")
|
ret.functionName = std::move(boost::get<Identifier>(_instruction));
|
||||||
);
|
ret.location = ret.functionName.location;
|
||||||
expectToken(Token::RParen);
|
expectToken(Token::LParen);
|
||||||
return ret;
|
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()
|
string Parser::expectAsmIdentifier()
|
||||||
|
@ -68,7 +68,7 @@ protected:
|
|||||||
Statement parseElementaryOperation(bool _onlySinglePusher = false);
|
Statement parseElementaryOperation(bool _onlySinglePusher = false);
|
||||||
VariableDeclaration parseVariableDeclaration();
|
VariableDeclaration parseVariableDeclaration();
|
||||||
FunctionDefinition parseFunctionDefinition();
|
FunctionDefinition parseFunctionDefinition();
|
||||||
FunctionalInstruction parseFunctionalInstruction(Statement&& _instruction);
|
Statement parseFunctionalInstruction(Statement&& _instruction);
|
||||||
std::string expectAsmIdentifier();
|
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_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_END()
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE(Printing)
|
BOOST_AUTO_TEST_SUITE(Printing)
|
||||||
|
Loading…
Reference in New Issue
Block a user