Merge pull request #2312 from ethereum/parser-cleanup

Parser cleanup (remove dependency on Solidity AST)
This commit is contained in:
chriseth 2017-05-29 14:04:01 +02:00 committed by GitHub
commit 4a5dc6a4ea
5 changed files with 87 additions and 94 deletions

View File

@ -50,16 +50,16 @@ assembly::Block Parser::parseBlock()
{ {
assembly::Block block = createWithLocation<Block>(); assembly::Block block = createWithLocation<Block>();
expectToken(Token::LBrace); expectToken(Token::LBrace);
while (m_scanner->currentToken() != Token::RBrace) while (currentToken() != Token::RBrace)
block.statements.emplace_back(parseStatement()); block.statements.emplace_back(parseStatement());
block.location.end = endPosition(); block.location.end = endPosition();
m_scanner->next(); advance();
return block; return block;
} }
assembly::Statement Parser::parseStatement() assembly::Statement Parser::parseStatement()
{ {
switch (m_scanner->currentToken()) switch (currentToken())
{ {
case Token::Let: case Token::Let:
return parseVariableDeclaration(); return parseVariableDeclaration();
@ -92,10 +92,10 @@ assembly::Statement Parser::parseStatement()
if (m_julia) if (m_julia)
break; break;
assembly::StackAssignment assignment = createWithLocation<assembly::StackAssignment>(); assembly::StackAssignment assignment = createWithLocation<assembly::StackAssignment>();
m_scanner->next(); advance();
expectToken(Token::Colon); expectToken(Token::Colon);
assignment.variableName.location = location(); assignment.variableName.location = location();
assignment.variableName.name = m_scanner->currentLiteral(); assignment.variableName.name = currentLiteral();
if (!m_julia && instructions().count(assignment.variableName.name)) if (!m_julia && instructions().count(assignment.variableName.name))
fatalParserError("Identifier expected, got instruction name."); fatalParserError("Identifier expected, got instruction name.");
assignment.location.end = endPosition(); assignment.location.end = endPosition();
@ -110,7 +110,7 @@ assembly::Statement Parser::parseStatement()
// literal, // literal,
// identifier (might turn into label or functional assignment) // identifier (might turn into label or functional assignment)
Statement statement(parseElementaryOperation(false)); Statement statement(parseElementaryOperation(false));
switch (m_scanner->currentToken()) switch (currentToken())
{ {
case Token::LParen: case Token::LParen:
return parseCall(std::move(statement)); return parseCall(std::move(statement));
@ -119,15 +119,15 @@ assembly::Statement Parser::parseStatement()
if (statement.type() != typeid(assembly::Identifier)) if (statement.type() != typeid(assembly::Identifier))
fatalParserError("Label name / variable name must precede \":\"."); fatalParserError("Label name / variable name must precede \":\".");
assembly::Identifier const& identifier = boost::get<assembly::Identifier>(statement); assembly::Identifier const& identifier = boost::get<assembly::Identifier>(statement);
m_scanner->next(); advance();
// identifier:=: should be parsed as identifier: =: (i.e. a label), // identifier:=: should be parsed as identifier: =: (i.e. a label),
// while identifier:= (being followed by a non-colon) as identifier := (assignment). // 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)
{ {
assembly::Assignment assignment = createWithLocation<assembly::Assignment>(identifier.location); assembly::Assignment assignment = createWithLocation<assembly::Assignment>(identifier.location);
if (!m_julia && instructions().count(identifier.name)) if (!m_julia && instructions().count(identifier.name))
fatalParserError("Cannot use instruction names for identifier names."); fatalParserError("Cannot use instruction names for identifier names.");
m_scanner->next(); advance();
assignment.variableName = identifier; assignment.variableName = identifier;
assignment.value.reset(new Statement(parseExpression())); assignment.value.reset(new Statement(parseExpression()));
assignment.location.end = locationOf(*assignment.value).end; assignment.location.end = locationOf(*assignment.value).end;
@ -174,7 +174,7 @@ assembly::Case Parser::parseCase()
assembly::Statement Parser::parseExpression() assembly::Statement Parser::parseExpression()
{ {
Statement operation = parseElementaryOperation(true); Statement operation = parseElementaryOperation(true);
if (m_scanner->currentToken() == Token::LParen) if (currentToken() == Token::LParen)
return parseCall(std::move(operation)); return parseCall(std::move(operation));
else else
return operation; return operation;
@ -207,7 +207,7 @@ std::map<string, dev::solidity::Instruction> const& Parser::instructions()
assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher) assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher)
{ {
Statement ret; Statement ret;
switch (m_scanner->currentToken()) switch (currentToken())
{ {
case Token::Identifier: case Token::Identifier:
case Token::Return: case Token::Return:
@ -215,14 +215,14 @@ assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher)
case Token::Address: case Token::Address:
{ {
string literal; string literal;
if (m_scanner->currentToken() == Token::Return) if (currentToken() == Token::Return)
literal = "return"; literal = "return";
else if (m_scanner->currentToken() == Token::Byte) else if (currentToken() == Token::Byte)
literal = "byte"; literal = "byte";
else if (m_scanner->currentToken() == Token::Address) else if (currentToken() == Token::Address)
literal = "address"; literal = "address";
else else
literal = m_scanner->currentLiteral(); literal = currentLiteral();
// first search the set of instructions. // first search the set of instructions.
if (!m_julia && instructions().count(literal)) if (!m_julia && instructions().count(literal))
{ {
@ -237,7 +237,7 @@ assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher)
} }
else else
ret = Identifier{location(), literal}; ret = Identifier{location(), literal};
m_scanner->next(); advance();
break; break;
} }
case Token::StringLiteral: case Token::StringLiteral:
@ -246,7 +246,7 @@ assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher)
case Token::FalseLiteral: case Token::FalseLiteral:
{ {
LiteralKind kind = LiteralKind::Number; LiteralKind kind = LiteralKind::Number;
switch (m_scanner->currentToken()) switch (currentToken())
{ {
case Token::StringLiteral: case Token::StringLiteral:
kind = LiteralKind::String; kind = LiteralKind::String;
@ -265,10 +265,10 @@ assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher)
Literal literal{ Literal literal{
location(), location(),
kind, kind,
m_scanner->currentLiteral(), currentLiteral(),
"" ""
}; };
m_scanner->next(); advance();
if (m_julia) if (m_julia)
{ {
expectToken(Token::Colon); expectToken(Token::Colon);
@ -297,7 +297,7 @@ assembly::VariableDeclaration Parser::parseVariableDeclaration()
while (true) while (true)
{ {
varDecl.variables.emplace_back(parseTypedName()); varDecl.variables.emplace_back(parseTypedName());
if (m_scanner->currentToken() == Token::Comma) if (currentToken() == Token::Comma)
expectToken(Token::Comma); expectToken(Token::Comma);
else else
break; break;
@ -315,22 +315,22 @@ assembly::FunctionDefinition Parser::parseFunctionDefinition()
expectToken(Token::Function); expectToken(Token::Function);
funDef.name = expectAsmIdentifier(); funDef.name = expectAsmIdentifier();
expectToken(Token::LParen); expectToken(Token::LParen);
while (m_scanner->currentToken() != Token::RParen) while (currentToken() != Token::RParen)
{ {
funDef.arguments.emplace_back(parseTypedName()); funDef.arguments.emplace_back(parseTypedName());
if (m_scanner->currentToken() == Token::RParen) if (currentToken() == Token::RParen)
break; break;
expectToken(Token::Comma); expectToken(Token::Comma);
} }
expectToken(Token::RParen); expectToken(Token::RParen);
if (m_scanner->currentToken() == Token::Sub) if (currentToken() == Token::Sub)
{ {
expectToken(Token::Sub); expectToken(Token::Sub);
expectToken(Token::GreaterThan); expectToken(Token::GreaterThan);
while (true) while (true)
{ {
funDef.returns.emplace_back(parseTypedName()); funDef.returns.emplace_back(parseTypedName());
if (m_scanner->currentToken() == Token::LBrace) if (currentToken() == Token::LBrace)
break; break;
expectToken(Token::Comma); expectToken(Token::Comma);
} }
@ -359,7 +359,7 @@ assembly::Statement Parser::parseCall(assembly::Statement&& _instruction)
for (unsigned i = 0; i < args; ++i) for (unsigned i = 0; i < args; ++i)
{ {
/// check for premature closing parentheses /// check for premature closing parentheses
if (m_scanner->currentToken() == Token::RParen) if (currentToken() == Token::RParen)
fatalParserError(string( fatalParserError(string(
"Expected expression (" + "Expected expression (" +
instrInfo.name + instrInfo.name +
@ -371,7 +371,7 @@ assembly::Statement Parser::parseCall(assembly::Statement&& _instruction)
ret.arguments.emplace_back(parseExpression()); ret.arguments.emplace_back(parseExpression());
if (i != args - 1) if (i != args - 1)
{ {
if (m_scanner->currentToken() != Token::Comma) if (currentToken() != Token::Comma)
fatalParserError(string( fatalParserError(string(
"Expected comma (" + "Expected comma (" +
instrInfo.name + instrInfo.name +
@ -380,11 +380,11 @@ assembly::Statement Parser::parseCall(assembly::Statement&& _instruction)
" arguments)" " arguments)"
)); ));
else else
m_scanner->next(); advance();
} }
} }
ret.location.end = endPosition(); ret.location.end = endPosition();
if (m_scanner->currentToken() == Token::Comma) if (currentToken() == Token::Comma)
fatalParserError( fatalParserError(
string("Expected ')' (" + instrInfo.name + " expects " + boost::lexical_cast<string>(args) + " arguments)") string("Expected ')' (" + instrInfo.name + " expects " + boost::lexical_cast<string>(args) + " arguments)")
); );
@ -397,10 +397,10 @@ assembly::Statement Parser::parseCall(assembly::Statement&& _instruction)
ret.functionName = std::move(boost::get<Identifier>(_instruction)); ret.functionName = std::move(boost::get<Identifier>(_instruction));
ret.location = ret.functionName.location; ret.location = ret.functionName.location;
expectToken(Token::LParen); expectToken(Token::LParen);
while (m_scanner->currentToken() != Token::RParen) while (currentToken() != Token::RParen)
{ {
ret.arguments.emplace_back(parseExpression()); ret.arguments.emplace_back(parseExpression());
if (m_scanner->currentToken() == Token::RParen) if (currentToken() == Token::RParen)
break; break;
expectToken(Token::Comma); expectToken(Token::Comma);
} }
@ -433,12 +433,12 @@ TypedName Parser::parseTypedName()
string Parser::expectAsmIdentifier() string Parser::expectAsmIdentifier()
{ {
string name = m_scanner->currentLiteral(); string name = currentLiteral();
if (m_julia) if (m_julia)
{ {
if (m_scanner->currentToken() == Token::Bool) if (currentToken() == Token::Bool)
{ {
m_scanner->next(); advance();
return name; return name;
} }
} }

View File

@ -1437,5 +1437,49 @@ ASTPointer<ParameterList> Parser::createEmptyParameterList()
return nodeFactory.createNode<ParameterList>(vector<ASTPointer<VariableDeclaration>>()); return nodeFactory.createNode<ParameterList>(vector<ASTPointer<VariableDeclaration>>());
} }
string Parser::currentTokenName()
{
Token::Value token = m_scanner->currentToken();
if (Token::isElementaryTypeName(token)) //for the sake of accuracy in reporting
{
ElementaryTypeNameToken elemTypeName = m_scanner->currentElementaryTypeNameToken();
return elemTypeName.toString();
}
else
return Token::name(token);
}
Token::Value Parser::expectAssignmentOperator()
{
Token::Value op = m_scanner->currentToken();
if (!Token::isAssignmentOp(op))
fatalParserError(
string("Expected assignment operator, got '") +
currentTokenName() +
string("'")
);
m_scanner->next();
return op;
}
ASTPointer<ASTString> Parser::expectIdentifierToken()
{
Token::Value id = m_scanner->currentToken();
if (id != Token::Identifier)
fatalParserError(
string("Expected identifier, got '") +
currentTokenName() +
string("'")
);
return getLiteralAndAdvance();
}
ASTPointer<ASTString> Parser::getLiteralAndAdvance()
{
ASTPointer<ASTString> identifier = make_shared<ASTString>(m_scanner->currentLiteral());
m_scanner->next();
return identifier;
}
} }
} }

View File

@ -154,6 +154,11 @@ private:
std::vector<ASTPointer<PrimaryExpression>> const& _path, std::vector<ASTPointer<PrimaryExpression>> const& _path,
std::vector<std::pair<ASTPointer<Expression>, SourceLocation>> const& _indices std::vector<std::pair<ASTPointer<Expression>, SourceLocation>> const& _indices
); );
std::string currentTokenName();
Token::Value expectAssignmentOperator();
ASTPointer<ASTString> expectIdentifierToken();
ASTPointer<ASTString> getLiteralAndAdvance();
///@} ///@}
/// Creates an empty ParameterList at the current location (used if parameters can be omitted). /// Creates an empty ParameterList at the current location (used if parameters can be omitted).

View File

@ -80,62 +80,6 @@ void ParserBase::expectToken(Token::Value _value)
m_scanner->next(); m_scanner->next();
} }
Token::Value ParserBase::expectAssignmentOperator()
{
Token::Value op = m_scanner->currentToken();
if (!Token::isAssignmentOp(op))
{
if (Token::isElementaryTypeName(op)) //for the sake of accuracy in reporting
{
ElementaryTypeNameToken elemTypeName = m_scanner->currentElementaryTypeNameToken();
fatalParserError(
string("Expected assignment operator, got '") +
elemTypeName.toString() +
string("'")
);
}
else
fatalParserError(
string("Expected assignment operator, got '") +
string(Token::name(m_scanner->currentToken())) +
string("'")
);
}
m_scanner->next();
return op;
}
ASTPointer<ASTString> ParserBase::expectIdentifierToken()
{
Token::Value id = m_scanner->currentToken();
if (id != Token::Identifier)
{
if (Token::isElementaryTypeName(id)) //for the sake of accuracy in reporting
{
ElementaryTypeNameToken elemTypeName = m_scanner->currentElementaryTypeNameToken();
fatalParserError(
string("Expected identifier, got '") +
elemTypeName.toString() +
string("'")
);
}
else
fatalParserError(
string("Expected identifier, got '") +
string(Token::name(id)) +
string("'")
);
}
return getLiteralAndAdvance();
}
ASTPointer<ASTString> ParserBase::getLiteralAndAdvance()
{
ASTPointer<ASTString> identifier = make_shared<ASTString>(m_scanner->currentLiteral());
m_scanner->next();
return identifier;
}
void ParserBase::parserError(string const& _description) void ParserBase::parserError(string const& _description)
{ {
auto err = make_shared<Error>(Error::Type::ParserError); auto err = make_shared<Error>(Error::Type::ParserError);

View File

@ -24,8 +24,8 @@
#include <memory> #include <memory>
#include <libsolidity/interface/Exceptions.h> #include <libsolidity/interface/Exceptions.h>
#include <libsolidity/parsing/Scanner.h>
#include <libsolidity/parsing/Token.h> #include <libsolidity/parsing/Token.h>
#include <libsolidity/ast/ASTForward.h>
namespace dev namespace dev
{ {
@ -47,14 +47,14 @@ protected:
/// End position of the current token /// End position of the current token
int endPosition() const; int endPosition() const;
///@{ ///@{
///@name Helper functions ///@name Helper functions
/// If current token value is not _value, throw exception otherwise advance token. /// If current token value is not _value, throw exception otherwise advance token.
void expectToken(Token::Value _value); void expectToken(Token::Value _value);
Token::Value expectAssignmentOperator(); Token::Value currentToken() const { return m_scanner->currentToken(); }
ASTPointer<ASTString> expectIdentifierToken(); Token::Value peekNextToken() const { return m_scanner->peekNextToken(); }
ASTPointer<ASTString> getLiteralAndAdvance(); std::string currentLiteral() const { return m_scanner->currentLiteral(); }
Token::Value advance() { return m_scanner->next(); }
///@} ///@}
/// Creates a @ref ParserError and annotates it with the current position and the /// Creates a @ref ParserError and annotates it with the current position and the