diff --git a/liblangutil/Scanner.cpp b/liblangutil/Scanner.cpp index 3463783bf1dc..9b609ceb0565 100644 --- a/liblangutil/Scanner.cpp +++ b/liblangutil/Scanner.cpp @@ -596,7 +596,12 @@ void Scanner::scanToken() token = Token::Period; break; case ':': - token = selectToken(Token::Colon); + // : := + advance(); + if (m_char == '=') + token = selectToken(Token::AssemblyAssign); + else + token = Token::Colon; break; case ';': token = selectToken(Token::Semicolon); diff --git a/liblangutil/Token.h b/liblangutil/Token.h index 6830e6c24747..35d4f76f339d 100644 --- a/liblangutil/Token.h +++ b/liblangutil/Token.h @@ -140,6 +140,8 @@ namespace langutil T(Dec, "--", 0) \ K(Delete, "delete", 0) \ \ + /* Inline Assembly Operators */ \ + T(AssemblyAssign, ":=", 2) \ /* Keywords */ \ K(Anonymous, "anonymous", 0) \ K(As, "as", 0) \ diff --git a/libyul/AsmParser.cpp b/libyul/AsmParser.cpp index 217c838a712b..993bf3d3e131 100644 --- a/libyul/AsmParser.cpp +++ b/libyul/AsmParser.cpp @@ -158,43 +158,49 @@ Statement Parser::parseStatement() } while (currentToken() == Token::Comma); - expectToken(Token::Colon); - expectToken(Token::Assign); + expectToken(Token::AssemblyAssign); + + assignment.value.reset(new Expression(parseExpression())); + assignment.location.end = locationOf(*assignment.value).end; + return Statement{std::move(assignment)}; + } + case Token::AssemblyAssign: + { + if (elementary.type() != typeid(Identifier)) + fatalParserError("Variable name must precede \":=\"."); + + Identifier const& identifier = boost::get(elementary); + Assignment assignment = createWithLocation(identifier.location); + + if (m_dialect->builtin(identifier.name)) + fatalParserError("Cannot assign to builtin function \"" + identifier.name.str() + "\"."); + else if (m_dialect->flavour != AsmFlavour::Yul && instructions().count(identifier.name.str())) + fatalParserError("Cannot use instruction names for identifier names."); + + advance(); + assignment.variableNames.emplace_back(identifier); assignment.value.reset(new Expression(parseExpression())); assignment.location.end = locationOf(*assignment.value).end; return Statement{std::move(assignment)}; + } case Token::Colon: { if (elementary.type() != typeid(Identifier)) - fatalParserError("Label name / variable name must precede \":\"."); + fatalParserError("Label name must precede \":\"."); + Identifier const& identifier = boost::get(elementary); + advance(); - // identifier:=: should be parsed as identifier: =: (i.e. a label), - // while identifier:= (being followed by a non-colon) as identifier := (assignment). - if (currentToken() == Token::Assign && peekNextToken() != Token::Colon) - { - Assignment assignment = createWithLocation(identifier.location); - if (m_dialect->builtin(identifier.name)) - fatalParserError("Cannot assign to builtin function \"" + identifier.name.str() + "\"."); - else if (m_dialect->flavour != AsmFlavour::Yul && instructions().count(identifier.name.str())) - fatalParserError("Cannot use instruction names for identifier names."); - advance(); - assignment.variableNames.emplace_back(identifier); - assignment.value.reset(new Expression(parseExpression())); - assignment.location.end = locationOf(*assignment.value).end; - return Statement{std::move(assignment)}; - } - else - { - // label - if (m_dialect->flavour != AsmFlavour::Loose) - fatalParserError("Labels are not supported."); - Label label = createWithLocation