mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Separate expression and statement.
This commit is contained in:
@@ -77,9 +77,7 @@ assembly::Statement Parser::parseStatement()
|
||||
{
|
||||
assembly::If _if = createWithLocation<assembly::If>();
|
||||
m_scanner->next();
|
||||
_if.condition = make_shared<Statement>(parseExpression());
|
||||
if (_if.condition->type() == typeid(assembly::Instruction))
|
||||
fatalParserError("Instructions are not supported as conditions for if - try to append \"()\".");
|
||||
_if.condition = make_shared<Expression>(parseExpression());
|
||||
_if.body = parseBlock();
|
||||
return _if;
|
||||
}
|
||||
@@ -87,9 +85,7 @@ assembly::Statement Parser::parseStatement()
|
||||
{
|
||||
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 - try to append \"()\".");
|
||||
_switch.expression = make_shared<Expression>(parseExpression());
|
||||
while (m_scanner->currentToken() == Token::Case)
|
||||
_switch.cases.emplace_back(parseCase());
|
||||
if (m_scanner->currentToken() == Token::Default)
|
||||
@@ -127,18 +123,21 @@ assembly::Statement Parser::parseStatement()
|
||||
// Simple instruction (might turn into functional),
|
||||
// literal,
|
||||
// identifier (might turn into label or functional assignment)
|
||||
Statement statement(parseElementaryOperation(false));
|
||||
ElementaryOperation elementary(parseElementaryOperation(false));
|
||||
switch (currentToken())
|
||||
{
|
||||
case Token::LParen:
|
||||
return parseCall(std::move(statement));
|
||||
{
|
||||
Expression expr = parseCall(std::move(elementary));
|
||||
return ExpressionStatement{locationOf(expr), expr};
|
||||
}
|
||||
case Token::Comma:
|
||||
{
|
||||
// if a comma follows, a multiple assignment is assumed
|
||||
|
||||
if (statement.type() != typeid(assembly::Identifier))
|
||||
if (elementary.type() != typeid(assembly::Identifier))
|
||||
fatalParserError("Label name / variable name must precede \",\" (multiple assignment).");
|
||||
assembly::Identifier const& identifier = boost::get<assembly::Identifier>(statement);
|
||||
assembly::Identifier const& identifier = boost::get<assembly::Identifier>(elementary);
|
||||
|
||||
Assignment assignment = createWithLocation<Assignment>(identifier.location);
|
||||
assignment.variableNames.emplace_back(identifier);
|
||||
@@ -146,25 +145,25 @@ assembly::Statement Parser::parseStatement()
|
||||
do
|
||||
{
|
||||
expectToken(Token::Comma);
|
||||
statement = parseElementaryOperation(false);
|
||||
if (statement.type() != typeid(assembly::Identifier))
|
||||
elementary = parseElementaryOperation(false);
|
||||
if (elementary.type() != typeid(assembly::Identifier))
|
||||
fatalParserError("Variable name expected in multiple assignemnt.");
|
||||
assignment.variableNames.emplace_back(boost::get<assembly::Identifier>(statement));
|
||||
assignment.variableNames.emplace_back(boost::get<assembly::Identifier>(elementary));
|
||||
}
|
||||
while (currentToken() == Token::Comma);
|
||||
|
||||
expectToken(Token::Colon);
|
||||
expectToken(Token::Assign);
|
||||
|
||||
assignment.value.reset(new Statement(parseExpression()));
|
||||
assignment.value.reset(new Expression(parseExpression()));
|
||||
assignment.location.end = locationOf(*assignment.value).end;
|
||||
return assignment;
|
||||
}
|
||||
case Token::Colon:
|
||||
{
|
||||
if (statement.type() != typeid(assembly::Identifier))
|
||||
if (elementary.type() != typeid(assembly::Identifier))
|
||||
fatalParserError("Label name / variable name must precede \":\".");
|
||||
assembly::Identifier const& identifier = boost::get<assembly::Identifier>(statement);
|
||||
assembly::Identifier const& identifier = boost::get<assembly::Identifier>(elementary);
|
||||
advance();
|
||||
// identifier:=: should be parsed as identifier: =: (i.e. a label),
|
||||
// while identifier:= (being followed by a non-colon) as identifier := (assignment).
|
||||
@@ -175,7 +174,7 @@ assembly::Statement Parser::parseStatement()
|
||||
fatalParserError("Cannot use instruction names for identifier names.");
|
||||
advance();
|
||||
assignment.variableNames.emplace_back(identifier);
|
||||
assignment.value.reset(new Statement(parseExpression()));
|
||||
assignment.value.reset(new Expression(parseExpression()));
|
||||
assignment.location.end = locationOf(*assignment.value).end;
|
||||
return assignment;
|
||||
}
|
||||
@@ -194,7 +193,21 @@ assembly::Statement Parser::parseStatement()
|
||||
fatalParserError("Call or assignment expected.");
|
||||
break;
|
||||
}
|
||||
return statement;
|
||||
if (elementary.type() == typeid(assembly::Identifier))
|
||||
{
|
||||
Expression expr = boost::get<assembly::Identifier>(elementary);
|
||||
return ExpressionStatement{locationOf(expr), expr};
|
||||
}
|
||||
else if (elementary.type() == typeid(assembly::Literal))
|
||||
{
|
||||
Expression expr = boost::get<assembly::Literal>(elementary);
|
||||
return ExpressionStatement{locationOf(expr), expr};
|
||||
}
|
||||
else
|
||||
{
|
||||
solAssert(elementary.type() == typeid(assembly::Instruction), "Invalid elementary operation.");
|
||||
return boost::get<assembly::Instruction>(elementary);
|
||||
}
|
||||
}
|
||||
|
||||
assembly::Case Parser::parseCase()
|
||||
@@ -206,10 +219,10 @@ assembly::Case Parser::parseCase()
|
||||
else if (m_scanner->currentToken() == Token::Case)
|
||||
{
|
||||
m_scanner->next();
|
||||
assembly::Statement statement = parseElementaryOperation();
|
||||
if (statement.type() != typeid(assembly::Literal))
|
||||
ElementaryOperation literal = parseElementaryOperation();
|
||||
if (literal.type() != typeid(assembly::Literal))
|
||||
fatalParserError("Literal expected.");
|
||||
_case.value = make_shared<Literal>(std::move(boost::get<assembly::Literal>(statement)));
|
||||
_case.value = make_shared<Literal>(boost::get<assembly::Literal>(std::move(literal)));
|
||||
}
|
||||
else
|
||||
fatalParserError("Case or default case expected.");
|
||||
@@ -224,19 +237,17 @@ assembly::ForLoop Parser::parseForLoop()
|
||||
ForLoop forLoop = createWithLocation<ForLoop>();
|
||||
expectToken(Token::For);
|
||||
forLoop.pre = parseBlock();
|
||||
forLoop.condition = make_shared<Statement>(parseExpression());
|
||||
if (forLoop.condition->type() == typeid(assembly::Instruction))
|
||||
fatalParserError("Instructions are not supported as conditions for the for statement.");
|
||||
forLoop.condition = make_shared<Expression>(parseExpression());
|
||||
forLoop.post = parseBlock();
|
||||
forLoop.body = parseBlock();
|
||||
forLoop.location.end = forLoop.body.location.end;
|
||||
return forLoop;
|
||||
}
|
||||
|
||||
assembly::Statement Parser::parseExpression()
|
||||
assembly::Expression Parser::parseExpression()
|
||||
{
|
||||
RecursionGuard recursionGuard(*this);
|
||||
Statement operation = parseElementaryOperation(true);
|
||||
ElementaryOperation operation = parseElementaryOperation(true);
|
||||
if (operation.type() == typeid(Instruction))
|
||||
{
|
||||
Instruction const& instr = boost::get<Instruction>(operation);
|
||||
@@ -252,8 +263,18 @@ assembly::Statement Parser::parseExpression()
|
||||
}
|
||||
if (currentToken() == Token::LParen)
|
||||
return parseCall(std::move(operation));
|
||||
else if (operation.type() == typeid(Instruction))
|
||||
{
|
||||
Instruction& instr = boost::get<Instruction>(operation);
|
||||
return FunctionalInstruction{std::move(instr.location), instr.instruction, {}};
|
||||
}
|
||||
else if (operation.type() == typeid(assembly::Identifier))
|
||||
return boost::get<assembly::Identifier>(operation);
|
||||
else
|
||||
return operation;
|
||||
{
|
||||
solAssert(operation.type() == typeid(assembly::Literal), "");
|
||||
return boost::get<assembly::Literal>(operation);
|
||||
}
|
||||
}
|
||||
|
||||
std::map<string, dev::solidity::Instruction> const& Parser::instructions()
|
||||
@@ -296,10 +317,10 @@ std::map<dev::solidity::Instruction, string> const& Parser::instructionNames()
|
||||
return s_instructionNames;
|
||||
}
|
||||
|
||||
assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher)
|
||||
Parser::ElementaryOperation Parser::parseElementaryOperation(bool _onlySinglePusher)
|
||||
{
|
||||
RecursionGuard recursionGuard(*this);
|
||||
Statement ret;
|
||||
ElementaryOperation ret;
|
||||
switch (currentToken())
|
||||
{
|
||||
case Token::Identifier:
|
||||
@@ -402,7 +423,7 @@ assembly::VariableDeclaration Parser::parseVariableDeclaration()
|
||||
{
|
||||
expectToken(Token::Colon);
|
||||
expectToken(Token::Assign);
|
||||
varDecl.value.reset(new Statement(parseExpression()));
|
||||
varDecl.value.reset(new Expression(parseExpression()));
|
||||
varDecl.location.end = locationOf(*varDecl.value).end;
|
||||
}
|
||||
else
|
||||
@@ -442,13 +463,13 @@ assembly::FunctionDefinition Parser::parseFunctionDefinition()
|
||||
return funDef;
|
||||
}
|
||||
|
||||
assembly::Statement Parser::parseCall(assembly::Statement&& _instruction)
|
||||
assembly::Expression Parser::parseCall(Parser::ElementaryOperation&& _initialOp)
|
||||
{
|
||||
RecursionGuard recursionGuard(*this);
|
||||
if (_instruction.type() == typeid(Instruction))
|
||||
if (_initialOp.type() == typeid(Instruction))
|
||||
{
|
||||
solAssert(!m_julia, "Instructions are invalid in JULIA");
|
||||
Instruction const& instruction = std::move(boost::get<Instruction>(_instruction));
|
||||
Instruction& instruction = boost::get<Instruction>(_initialOp);
|
||||
FunctionalInstruction ret;
|
||||
ret.instruction = instruction.instruction;
|
||||
ret.location = std::move(instruction.location);
|
||||
@@ -499,10 +520,10 @@ assembly::Statement Parser::parseCall(assembly::Statement&& _instruction)
|
||||
expectToken(Token::RParen);
|
||||
return ret;
|
||||
}
|
||||
else if (_instruction.type() == typeid(Identifier))
|
||||
else if (_initialOp.type() == typeid(Identifier))
|
||||
{
|
||||
FunctionCall ret;
|
||||
ret.functionName = std::move(boost::get<Identifier>(_instruction));
|
||||
ret.functionName = std::move(boost::get<Identifier>(_initialOp));
|
||||
ret.location = ret.functionName.location;
|
||||
expectToken(Token::LParen);
|
||||
while (currentToken() != Token::RParen)
|
||||
|
||||
Reference in New Issue
Block a user