diff options
Diffstat (limited to 'libsolidity/inlineasm/AsmParser.cpp')
-rw-r--r-- | libsolidity/inlineasm/AsmParser.cpp | 145 |
1 files changed, 99 insertions, 46 deletions
diff --git a/libsolidity/inlineasm/AsmParser.cpp b/libsolidity/inlineasm/AsmParser.cpp index a96984f5..80409c63 100644 --- a/libsolidity/inlineasm/AsmParser.cpp +++ b/libsolidity/inlineasm/AsmParser.cpp @@ -50,16 +50,16 @@ assembly::Block Parser::parseBlock() { assembly::Block block = createWithLocation<Block>(); expectToken(Token::LBrace); - while (m_scanner->currentToken() != Token::RBrace) + while (currentToken() != Token::RBrace) block.statements.emplace_back(parseStatement()); block.location.end = endPosition(); - m_scanner->next(); + advance(); return block; } assembly::Statement Parser::parseStatement() { - switch (m_scanner->currentToken()) + switch (currentToken()) { case Token::Let: return parseVariableDeclaration(); @@ -67,24 +67,41 @@ assembly::Statement Parser::parseStatement() return parseFunctionDefinition(); case Token::LBrace: return parseBlock(); + case Token::Switch: + { + assembly::Switch _switch = createWithLocation<assembly::Switch>(); + m_scanner->next(); + _switch.expression = make_shared<Statement>(parseExpression()); + if (_switch.expression->type() == typeid(assembly::Instruction)) + fatalParserError("Instructions are not supported as expressions for switch."); + while (m_scanner->currentToken() == Token::Case) + _switch.cases.emplace_back(parseCase()); + if (m_scanner->currentToken() == Token::Default) + _switch.cases.emplace_back(parseCase()); + if (m_scanner->currentToken() == Token::Default) + fatalParserError("Only one default case allowed."); + else if (m_scanner->currentToken() == Token::Case) + fatalParserError("Case not allowed after default case."); + if (_switch.cases.size() == 0) + fatalParserError("Switch statement without any cases."); + _switch.location.end = _switch.cases.back().body.location.end; + return _switch; + } case Token::Assign: { if (m_julia) break; - assembly::Assignment assignment = createWithLocation<assembly::Assignment>(); - m_scanner->next(); + assembly::StackAssignment assignment = createWithLocation<assembly::StackAssignment>(); + advance(); expectToken(Token::Colon); assignment.variableName.location = location(); - assignment.variableName.name = m_scanner->currentLiteral(); + assignment.variableName.name = currentLiteral(); if (!m_julia && instructions().count(assignment.variableName.name)) fatalParserError("Identifier expected, got instruction name."); assignment.location.end = endPosition(); expectToken(Token::Identifier); return assignment; } - case Token::Return: // opcode - case Token::Byte: // opcode - case Token::Address: // opcode default: break; } @@ -93,29 +110,28 @@ assembly::Statement Parser::parseStatement() // literal, // identifier (might turn into label or functional assignment) Statement statement(parseElementaryOperation(false)); - switch (m_scanner->currentToken()) + switch (currentToken()) { case Token::LParen: - return parseFunctionalInstruction(std::move(statement)); + return parseCall(std::move(statement)); case Token::Colon: { if (statement.type() != typeid(assembly::Identifier)) fatalParserError("Label name / variable name must precede \":\"."); assembly::Identifier const& identifier = boost::get<assembly::Identifier>(statement); - m_scanner->next(); + advance(); // identifier:=: should be parsed as identifier: =: (i.e. a label), // while identifier:= (being followed by a non-colon) as identifier := (assignment). - if (m_scanner->currentToken() == Token::Assign && m_scanner->peekNextToken() != Token::Colon) + if (currentToken() == Token::Assign && peekNextToken() != Token::Colon) { - // functional assignment - FunctionalAssignment funAss = createWithLocation<FunctionalAssignment>(identifier.location); + assembly::Assignment assignment = createWithLocation<assembly::Assignment>(identifier.location); if (!m_julia && instructions().count(identifier.name)) fatalParserError("Cannot use instruction names for identifier names."); - m_scanner->next(); - funAss.variableName = identifier; - funAss.value.reset(new Statement(parseExpression())); - funAss.location.end = locationOf(*funAss.value).end; - return funAss; + advance(); + assignment.variableName = identifier; + assignment.value.reset(new Statement(parseExpression())); + assignment.location.end = locationOf(*assignment.value).end; + return assignment; } else { @@ -135,11 +151,31 @@ assembly::Statement Parser::parseStatement() return statement; } +assembly::Case Parser::parseCase() +{ + assembly::Case _case = createWithLocation<assembly::Case>(); + if (m_scanner->currentToken() == Token::Default) + m_scanner->next(); + else if (m_scanner->currentToken() == Token::Case) + { + m_scanner->next(); + assembly::Statement statement = parseElementaryOperation(); + if (statement.type() != typeid(assembly::Literal)) + fatalParserError("Literal expected."); + _case.value = make_shared<Literal>(std::move(boost::get<assembly::Literal>(statement))); + } + else + fatalParserError("Case or default case expected."); + _case.body = parseBlock(); + _case.location.end = _case.body.location.end; + return _case; +} + assembly::Statement Parser::parseExpression() { Statement operation = parseElementaryOperation(true); - if (m_scanner->currentToken() == Token::LParen) - return parseFunctionalInstruction(std::move(operation)); + if (currentToken() == Token::LParen) + return parseCall(std::move(operation)); else return operation; } @@ -171,7 +207,7 @@ std::map<string, dev::solidity::Instruction> const& Parser::instructions() assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher) { Statement ret; - switch (m_scanner->currentToken()) + switch (currentToken()) { case Token::Identifier: case Token::Return: @@ -179,14 +215,14 @@ assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher) case Token::Address: { string literal; - if (m_scanner->currentToken() == Token::Return) + if (currentToken() == Token::Return) literal = "return"; - else if (m_scanner->currentToken() == Token::Byte) + else if (currentToken() == Token::Byte) literal = "byte"; - else if (m_scanner->currentToken() == Token::Address) + else if (currentToken() == Token::Address) literal = "address"; else - literal = m_scanner->currentLiteral(); + literal = currentLiteral(); // first search the set of instructions. if (!m_julia && instructions().count(literal)) { @@ -201,7 +237,7 @@ assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher) } else ret = Identifier{location(), literal}; - m_scanner->next(); + advance(); break; } case Token::StringLiteral: @@ -210,7 +246,7 @@ assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher) case Token::FalseLiteral: { LiteralKind kind = LiteralKind::Number; - switch (m_scanner->currentToken()) + switch (currentToken()) { case Token::StringLiteral: kind = LiteralKind::String; @@ -229,10 +265,10 @@ assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher) Literal literal{ location(), kind, - m_scanner->currentLiteral(), + currentLiteral(), "" }; - m_scanner->next(); + advance(); if (m_julia) { expectToken(Token::Colon); @@ -248,7 +284,7 @@ assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher) fatalParserError( m_julia ? "Literal or identifier expected." : - "Expected elementary inline assembly operation." + "Literal, identifier or instruction expected." ); } return ret; @@ -258,7 +294,14 @@ assembly::VariableDeclaration Parser::parseVariableDeclaration() { VariableDeclaration varDecl = createWithLocation<VariableDeclaration>(); expectToken(Token::Let); - varDecl.variable = parseTypedName(); + while (true) + { + varDecl.variables.emplace_back(parseTypedName()); + if (currentToken() == Token::Comma) + expectToken(Token::Comma); + else + break; + } expectToken(Token::Colon); expectToken(Token::Assign); varDecl.value.reset(new Statement(parseExpression())); @@ -272,22 +315,22 @@ assembly::FunctionDefinition Parser::parseFunctionDefinition() expectToken(Token::Function); funDef.name = expectAsmIdentifier(); expectToken(Token::LParen); - while (m_scanner->currentToken() != Token::RParen) + while (currentToken() != Token::RParen) { funDef.arguments.emplace_back(parseTypedName()); - if (m_scanner->currentToken() == Token::RParen) + if (currentToken() == Token::RParen) break; expectToken(Token::Comma); } expectToken(Token::RParen); - if (m_scanner->currentToken() == Token::Sub) + if (currentToken() == Token::Sub) { expectToken(Token::Sub); expectToken(Token::GreaterThan); while (true) { funDef.returns.emplace_back(parseTypedName()); - if (m_scanner->currentToken() == Token::LBrace) + if (currentToken() == Token::LBrace) break; expectToken(Token::Comma); } @@ -297,7 +340,7 @@ assembly::FunctionDefinition Parser::parseFunctionDefinition() return funDef; } -assembly::Statement Parser::parseFunctionalInstruction(assembly::Statement&& _instruction) +assembly::Statement Parser::parseCall(assembly::Statement&& _instruction) { if (_instruction.type() == typeid(Instruction)) { @@ -315,10 +358,20 @@ assembly::Statement Parser::parseFunctionalInstruction(assembly::Statement&& _in unsigned args = unsigned(instrInfo.args); for (unsigned i = 0; i < args; ++i) { + /// check for premature closing parentheses + if (currentToken() == Token::RParen) + fatalParserError(string( + "Expected expression (" + + instrInfo.name + + " expects " + + boost::lexical_cast<string>(args) + + " arguments)" + )); + ret.arguments.emplace_back(parseExpression()); if (i != args - 1) { - if (m_scanner->currentToken() != Token::Comma) + if (currentToken() != Token::Comma) fatalParserError(string( "Expected comma (" + instrInfo.name + @@ -327,11 +380,11 @@ assembly::Statement Parser::parseFunctionalInstruction(assembly::Statement&& _in " arguments)" )); else - m_scanner->next(); + advance(); } } ret.location.end = endPosition(); - if (m_scanner->currentToken() == Token::Comma) + if (currentToken() == Token::Comma) fatalParserError( string("Expected ')' (" + instrInfo.name + " expects " + boost::lexical_cast<string>(args) + " arguments)") ); @@ -344,10 +397,10 @@ assembly::Statement Parser::parseFunctionalInstruction(assembly::Statement&& _in ret.functionName = std::move(boost::get<Identifier>(_instruction)); ret.location = ret.functionName.location; expectToken(Token::LParen); - while (m_scanner->currentToken() != Token::RParen) + while (currentToken() != Token::RParen) { ret.arguments.emplace_back(parseExpression()); - if (m_scanner->currentToken() == Token::RParen) + if (currentToken() == Token::RParen) break; expectToken(Token::Comma); } @@ -380,12 +433,12 @@ TypedName Parser::parseTypedName() string Parser::expectAsmIdentifier() { - string name = m_scanner->currentLiteral(); + string name = currentLiteral(); if (m_julia) { - if (m_scanner->currentToken() == Token::Bool) + if (currentToken() == Token::Bool) { - m_scanner->next(); + advance(); return name; } } |