mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Parsing function definitions.
This commit is contained in:
parent
ad751bd3e6
commit
5d584aded8
@ -249,7 +249,10 @@ public:
|
|||||||
_block.location
|
_block.location
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
void operator()(assembly::FunctionDefinition const&)
|
||||||
|
{
|
||||||
|
solAssert(false, "Function definition not removed during desugaring phase.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -48,8 +48,9 @@ struct Label { SourceLocation location; std::string name; };
|
|||||||
struct Assignment { SourceLocation location; Identifier variableName; };
|
struct Assignment { SourceLocation location; Identifier variableName; };
|
||||||
struct FunctionalAssignment;
|
struct FunctionalAssignment;
|
||||||
struct VariableDeclaration;
|
struct VariableDeclaration;
|
||||||
|
struct FunctionDefinition;
|
||||||
struct Block;
|
struct Block;
|
||||||
using Statement = boost::variant<Instruction, Literal, Label, Assignment, Identifier, FunctionalAssignment, FunctionalInstruction, VariableDeclaration, Block>;
|
using Statement = boost::variant<Instruction, Literal, Label, Assignment, Identifier, FunctionalAssignment, 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; };
|
||||||
@ -59,6 +60,8 @@ struct FunctionalInstruction { SourceLocation location; Instruction instruction;
|
|||||||
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)
|
||||||
struct Block { SourceLocation location; std::vector<Statement> statements; };
|
struct Block { SourceLocation location; std::vector<Statement> statements; };
|
||||||
|
/// Function definition ("function f(a, b) -> (d, e) { ... }")
|
||||||
|
struct FunctionDefinition { SourceLocation location; std::string name; std::vector<std::string> arguments; std::vector<std::string> returns; Block body; };
|
||||||
|
|
||||||
struct LocationExtractor: boost::static_visitor<SourceLocation>
|
struct LocationExtractor: boost::static_visitor<SourceLocation>
|
||||||
{
|
{
|
||||||
|
@ -62,6 +62,8 @@ assembly::Statement Parser::parseStatement()
|
|||||||
{
|
{
|
||||||
case Token::Let:
|
case Token::Let:
|
||||||
return parseVariableDeclaration();
|
return parseVariableDeclaration();
|
||||||
|
case Token::Function:
|
||||||
|
return parseFunctionDefinition();
|
||||||
case Token::LBrace:
|
case Token::LBrace:
|
||||||
return parseBlock();
|
return parseBlock();
|
||||||
case Token::Assign:
|
case Token::Assign:
|
||||||
@ -214,10 +216,7 @@ assembly::VariableDeclaration Parser::parseVariableDeclaration()
|
|||||||
{
|
{
|
||||||
VariableDeclaration varDecl = createWithLocation<VariableDeclaration>();
|
VariableDeclaration varDecl = createWithLocation<VariableDeclaration>();
|
||||||
expectToken(Token::Let);
|
expectToken(Token::Let);
|
||||||
varDecl.name = m_scanner->currentLiteral();
|
varDecl.name = expectAsmIdentifier();
|
||||||
if (instructions().count(varDecl.name))
|
|
||||||
fatalParserError("Cannot use instruction names for identifier names.");
|
|
||||||
expectToken(Token::Identifier);
|
|
||||||
expectToken(Token::Colon);
|
expectToken(Token::Colon);
|
||||||
expectToken(Token::Assign);
|
expectToken(Token::Assign);
|
||||||
varDecl.value.reset(new Statement(parseExpression()));
|
varDecl.value.reset(new Statement(parseExpression()));
|
||||||
@ -225,6 +224,39 @@ assembly::VariableDeclaration Parser::parseVariableDeclaration()
|
|||||||
return varDecl;
|
return varDecl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assembly::FunctionDefinition Parser::parseFunctionDefinition()
|
||||||
|
{
|
||||||
|
FunctionDefinition funDef = createWithLocation<FunctionDefinition>();
|
||||||
|
expectToken(Token::Function);
|
||||||
|
funDef.name = expectAsmIdentifier();
|
||||||
|
expectToken(Token::LParen);
|
||||||
|
while (m_scanner->currentToken() != Token::RParen)
|
||||||
|
{
|
||||||
|
funDef.arguments.push_back(expectAsmIdentifier());
|
||||||
|
if (m_scanner->currentToken() == Token::RParen)
|
||||||
|
break;
|
||||||
|
expectToken(Token::Comma);
|
||||||
|
}
|
||||||
|
expectToken(Token::RParen);
|
||||||
|
if (m_scanner->currentToken() == Token::Sub)
|
||||||
|
{
|
||||||
|
expectToken(Token::Sub);
|
||||||
|
expectToken(Token::GreaterThan);
|
||||||
|
expectToken(Token::LParen);
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
funDef.returns.push_back(expectAsmIdentifier());
|
||||||
|
if (m_scanner->currentToken() == Token::RParen)
|
||||||
|
break;
|
||||||
|
expectToken(Token::Comma);
|
||||||
|
}
|
||||||
|
expectToken(Token::RParen);
|
||||||
|
}
|
||||||
|
funDef.body = parseBlock();
|
||||||
|
funDef.location.end = funDef.body.location.end;
|
||||||
|
return funDef;
|
||||||
|
}
|
||||||
|
|
||||||
FunctionalInstruction Parser::parseFunctionalInstruction(assembly::Statement&& _instruction)
|
FunctionalInstruction Parser::parseFunctionalInstruction(assembly::Statement&& _instruction)
|
||||||
{
|
{
|
||||||
if (_instruction.type() != typeid(Instruction))
|
if (_instruction.type() != typeid(Instruction))
|
||||||
@ -266,3 +298,12 @@ FunctionalInstruction Parser::parseFunctionalInstruction(assembly::Statement&& _
|
|||||||
expectToken(Token::RParen);
|
expectToken(Token::RParen);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string Parser::expectAsmIdentifier()
|
||||||
|
{
|
||||||
|
string name = m_scanner->currentLiteral();
|
||||||
|
if (instructions().count(name))
|
||||||
|
fatalParserError("Cannot use instruction names for identifier names.");
|
||||||
|
expectToken(Token::Identifier);
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
@ -67,7 +67,9 @@ protected:
|
|||||||
std::map<std::string, dev::solidity::Instruction> const& instructions();
|
std::map<std::string, dev::solidity::Instruction> const& instructions();
|
||||||
Statement parseElementaryOperation(bool _onlySinglePusher = false);
|
Statement parseElementaryOperation(bool _onlySinglePusher = false);
|
||||||
VariableDeclaration parseVariableDeclaration();
|
VariableDeclaration parseVariableDeclaration();
|
||||||
|
FunctionDefinition parseFunctionDefinition();
|
||||||
FunctionalInstruction parseFunctionalInstruction(Statement&& _instruction);
|
FunctionalInstruction parseFunctionalInstruction(Statement&& _instruction);
|
||||||
|
std::string expectAsmIdentifier();
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -159,6 +159,16 @@ BOOST_AUTO_TEST_CASE(blocks)
|
|||||||
BOOST_CHECK(successParse("{ let x := 7 { let y := 3 } { let z := 2 } }"));
|
BOOST_CHECK(successParse("{ let x := 7 { let y := 3 } { let z := 2 } }"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(function_definitions)
|
||||||
|
{
|
||||||
|
BOOST_CHECK(successParse("{ function f() { } function g(a) -> (x) { } }"));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(function_definitions_multiple_args)
|
||||||
|
{
|
||||||
|
BOOST_CHECK(successParse("{ function f(a, d) { } function g(a, d) -> (x, y) { } }"));
|
||||||
|
}
|
||||||
|
|
||||||
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