Merge pull request #9555 from ethereum/yul-parser-refactor

Yul parser refactor
This commit is contained in:
chriseth 2020-12-03 18:07:31 +01:00 committed by GitHub
commit e04cc80438
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 56 additions and 78 deletions

View File

@ -27,6 +27,7 @@
#include <liblangutil/Scanner.h> #include <liblangutil/Scanner.h>
#include <liblangutil/ErrorReporter.h> #include <liblangutil/ErrorReporter.h>
#include <libsolutil/Common.h> #include <libsolutil/Common.h>
#include <libsolutil/Visitor.h>
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
@ -138,18 +139,18 @@ Statement Parser::parseStatement()
default: default:
break; break;
} }
// Options left: // Options left:
// Simple instruction (might turn into functional), // Expression/FunctionCall
// literal, // Assignment
// identifier (might turn into label or functional assignment) variant<Literal, Identifier> elementary(parseLiteralOrIdentifier());
ElementaryOperation elementary(parseElementaryOperation());
switch (currentToken()) switch (currentToken())
{ {
case Token::LParen: case Token::LParen:
{ {
Expression expr = parseCall(std::move(elementary)); Expression expr = parseCall(std::move(elementary));
return ExpressionStatement{locationOf(expr), expr}; return ExpressionStatement{locationOf(expr), move(expr)};
} }
case Token::Comma: case Token::Comma:
case Token::AssemblyAssign: case Token::AssemblyAssign:
@ -184,7 +185,7 @@ Statement Parser::parseStatement()
expectToken(Token::Comma); expectToken(Token::Comma);
elementary = parseElementaryOperation(); elementary = parseLiteralOrIdentifier();
} }
expectToken(Token::AssemblyAssign); expectToken(Token::AssemblyAssign);
@ -192,28 +193,15 @@ Statement Parser::parseStatement()
assignment.value = make_unique<Expression>(parseExpression()); assignment.value = make_unique<Expression>(parseExpression());
assignment.location.end = locationOf(*assignment.value).end; assignment.location.end = locationOf(*assignment.value).end;
return Statement{std::move(assignment)}; return Statement{move(assignment)};
} }
default: default:
fatalParserError(6913_error, "Call or assignment expected."); fatalParserError(6913_error, "Call or assignment expected.");
break; break;
} }
if (holds_alternative<Identifier>(elementary)) yulAssert(false, "");
{ return {};
Identifier& identifier = std::get<Identifier>(elementary);
return ExpressionStatement{identifier.location, { move(identifier) }};
}
else if (holds_alternative<Literal>(elementary))
{
Expression expr = std::get<Literal>(elementary);
return ExpressionStatement{locationOf(expr), expr};
}
else
{
yulAssert(false, "Invalid elementary operation.");
return {};
}
} }
Case Parser::parseCase() Case Parser::parseCase()
@ -225,7 +213,7 @@ Case Parser::parseCase()
else if (currentToken() == Token::Case) else if (currentToken() == Token::Case)
{ {
advance(); advance();
ElementaryOperation literal = parseElementaryOperation(); variant<Literal, Identifier> literal = parseLiteralOrIdentifier();
if (!holds_alternative<Literal>(literal)) if (!holds_alternative<Literal>(literal))
fatalParserError(4805_error, "Literal expected."); fatalParserError(4805_error, "Literal expected.");
_case.value = make_unique<Literal>(std::get<Literal>(std::move(literal))); _case.value = make_unique<Literal>(std::get<Literal>(std::move(literal)));
@ -264,38 +252,37 @@ Expression Parser::parseExpression()
{ {
RecursionGuard recursionGuard(*this); RecursionGuard recursionGuard(*this);
ElementaryOperation operation = parseElementaryOperation(); variant<Literal, Identifier> operation = parseLiteralOrIdentifier();
if (holds_alternative<FunctionCall>(operation) || currentToken() == Token::LParen) return visit(GenericVisitor{
return parseCall(std::move(operation)); [&](Identifier& _identifier) -> Expression
else if (holds_alternative<Identifier>(operation)) {
return std::get<Identifier>(operation); if (currentToken() == Token::LParen)
else return parseCall(std::move(operation));
{ if (m_dialect.builtin(_identifier.name))
yulAssert(holds_alternative<Literal>(operation), ""); fatalParserError(
return std::get<Literal>(operation); 7104_error,
} _identifier.location,
"Builtin function \"" + _identifier.name.str() + "\" must be called."
);
return move(_identifier);
},
[&](Literal& _literal) -> Expression
{
return move(_literal);
}
}, operation);
} }
Parser::ElementaryOperation Parser::parseElementaryOperation() variant<Literal, Identifier> Parser::parseLiteralOrIdentifier()
{ {
RecursionGuard recursionGuard(*this); RecursionGuard recursionGuard(*this);
ElementaryOperation ret;
switch (currentToken()) switch (currentToken())
{ {
case Token::Identifier: case Token::Identifier:
{ {
YulString literal{currentLiteral()}; Identifier identifier{currentLocation(), YulString{currentLiteral()}};
if (m_dialect.builtin(literal))
{
Identifier identifier{currentLocation(), literal};
advance();
expectToken(Token::LParen, false);
return FunctionCall{identifier.location, identifier, {}};
}
else
ret = Identifier{currentLocation(), literal};
advance(); advance();
break; return identifier;
} }
case Token::StringLiteral: case Token::StringLiteral:
case Token::Number: case Token::Number:
@ -335,8 +322,7 @@ Parser::ElementaryOperation Parser::parseElementaryOperation()
literal.type = expectAsmIdentifier(); literal.type = expectAsmIdentifier();
} }
ret = std::move(literal); return literal;
break;
} }
case Token::HexStringLiteral: case Token::HexStringLiteral:
fatalParserError(3772_error, "Hex literals are not valid in this context."); fatalParserError(3772_error, "Hex literals are not valid in this context.");
@ -344,7 +330,7 @@ Parser::ElementaryOperation Parser::parseElementaryOperation()
default: default:
fatalParserError(1856_error, "Literal or identifier expected."); fatalParserError(1856_error, "Literal or identifier expected.");
} }
return ret; return {};
} }
VariableDeclaration Parser::parseVariableDeclaration() VariableDeclaration Parser::parseVariableDeclaration()
@ -418,21 +404,17 @@ FunctionDefinition Parser::parseFunctionDefinition()
return funDef; return funDef;
} }
Expression Parser::parseCall(Parser::ElementaryOperation&& _initialOp) FunctionCall Parser::parseCall(variant<Literal, Identifier>&& _initialOp)
{ {
RecursionGuard recursionGuard(*this); RecursionGuard recursionGuard(*this);
FunctionCall ret; if (!holds_alternative<Identifier>(_initialOp))
if (holds_alternative<Identifier>(_initialOp))
{
ret.functionName = std::move(std::get<Identifier>(_initialOp));
ret.location = ret.functionName.location;
}
else if (holds_alternative<FunctionCall>(_initialOp))
ret = std::move(std::get<FunctionCall>(_initialOp));
else
fatalParserError(9980_error, "Function name expected."); fatalParserError(9980_error, "Function name expected.");
FunctionCall ret;
ret.functionName = std::move(std::get<Identifier>(_initialOp));
ret.location = ret.functionName.location;
expectToken(Token::LParen); expectToken(Token::LParen);
if (currentToken() != Token::RParen) if (currentToken() != Token::RParen)
{ {

View File

@ -61,8 +61,6 @@ public:
std::unique_ptr<Block> parse(std::shared_ptr<langutil::Scanner> const& _scanner, bool _reuseScanner); std::unique_ptr<Block> parse(std::shared_ptr<langutil::Scanner> const& _scanner, bool _reuseScanner);
protected: protected:
using ElementaryOperation = std::variant<Literal, Identifier, FunctionCall>;
langutil::SourceLocation currentLocation() const override langutil::SourceLocation currentLocation() const override
{ {
return m_locationOverride ? *m_locationOverride : ParserBase::currentLocation(); return m_locationOverride ? *m_locationOverride : ParserBase::currentLocation();
@ -84,10 +82,10 @@ protected:
Expression parseExpression(); Expression parseExpression();
/// Parses an elementary operation, i.e. a literal, identifier, instruction or /// Parses an elementary operation, i.e. a literal, identifier, instruction or
/// builtin functian call (only the name). /// builtin functian call (only the name).
ElementaryOperation parseElementaryOperation(); std::variant<Literal, Identifier> parseLiteralOrIdentifier();
VariableDeclaration parseVariableDeclaration(); VariableDeclaration parseVariableDeclaration();
FunctionDefinition parseFunctionDefinition(); FunctionDefinition parseFunctionDefinition();
Expression parseCall(ElementaryOperation&& _initialOp); FunctionCall parseCall(std::variant<Literal, Identifier>&& _initialOp);
TypedName parseTypedName(); TypedName parseTypedName();
YulString expectAsmIdentifier(); YulString expectAsmIdentifier();

View File

@ -223,7 +223,7 @@ def examine_id_coverage(top_dir, source_id_to_file_names, new_ids_only=False):
"1123", "1220", "1584", "1823", "1123", "1220", "1584", "1823",
"1988", "2657", "2800", "3356", "1988", "2657", "2800", "3356",
"3893", "3996", "4010", "4802", "3893", "3996", "4010", "4802",
"5073", "5272", "5622", "6272", "7128", "5073", "5272", "5622", "7128",
"7589", "7593", "7653", "8065", "8084", "8140", "7589", "7593", "7653", "8065", "8084", "8140",
"8312", "8592", "9085", "9390" "8312", "8592", "9085", "9390"
} }

View File

@ -7,4 +7,4 @@ contract C {
} }
} }
// ---- // ----
// ParserError 2314: (118-119): Expected '(' but got '}' // ParserError 7104: (104-109): Builtin function "mload" must be called.

View File

@ -7,4 +7,4 @@ contract C {
} }
} }
// ---- // ----
// ParserError 2314: (101-103): Expected '(' but got ':=' // ParserError 6272: (101-103): Cannot assign to builtin function "mload".

View File

@ -7,4 +7,4 @@ contract C {
} }
} }
// ---- // ----
// ParserError 2314: (95-98): Expected '(' but got identifier // ParserError 6913: (95-98): Call or assignment expected.

View File

@ -6,4 +6,4 @@ contract test {
} }
} }
// ---- // ----
// ParserError 2314: (85-86): Expected '(' but got '}' // ParserError 6913: (85-86): Call or assignment expected.

View File

@ -2,4 +2,4 @@
function f(x) { f(add) } function f(x) { f(add) }
} }
// ---- // ----
// ParserError 2314: (24-25): Expected '(' but got ')' // ParserError 7104: (21-24): Builtin function "add" must be called.

View File

@ -1,6 +1,5 @@
{ {
// Test for the unreachable 6272_error
add := 1 add := 1
} }
// ---- // ----
// ParserError 2314: (47-49): Expected '(' but got ':=' // ParserError 6272: (7-9): Cannot assign to builtin function "add".

View File

@ -1,7 +1,6 @@
{ {
// Test for the unreachable 6272_error
function f() -> a, b {} function f() -> a, b {}
add, mul := f() add, mul := f()
} }
// ---- // ----
// ParserError 2314: (71-72): Expected '(' but got ',' // ParserError 6272: (31-32): Cannot assign to builtin function "add".

View File

@ -2,4 +2,4 @@
for {} mload {} {} for {} mload {} {}
} }
// ---- // ----
// ParserError 2314: (16-17): Expected '(' but got '{' // ParserError 7104: (10-15): Builtin function "mload" must be called.

View File

@ -2,4 +2,4 @@
let x := byte let x := byte
} }
// ---- // ----
// ParserError 2314: (20-21): Expected '(' but got '}' // ParserError 7104: (15-19): Builtin function "byte" must be called.

View File

@ -2,4 +2,4 @@
if mload {} if mload {}
} }
// ---- // ----
// ParserError 2314: (15-16): Expected '(' but got '{' // ParserError 7104: (9-14): Builtin function "mload" must be called.

View File

@ -2,4 +2,4 @@
if calldatasize {} if calldatasize {}
} }
// ---- // ----
// ParserError 2314: (22-23): Expected '(' but got '{' // ParserError 7104: (9-21): Builtin function "calldatasize" must be called.

View File

@ -4,4 +4,4 @@
default {} default {}
} }
// ---- // ----
// ParserError 2314: (23-27): Expected '(' but got reserved keyword 'case' // ParserError 7104: (13-18): Builtin function "mload" must be called.