Parsing function definitions.

This commit is contained in:
chriseth 2017-01-31 23:59:41 +01:00
parent ad751bd3e6
commit 5d584aded8
5 changed files with 65 additions and 6 deletions

View File

@ -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:

View File

@ -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>
{ {

View File

@ -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;
}

View File

@ -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();
}; };
} }

View File

@ -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)