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..0e0801decba4 100644 --- a/liblangutil/Token.h +++ b/liblangutil/Token.h @@ -88,6 +88,7 @@ namespace langutil /* Assignment operators. */ \ /* IsAssignmentOp() relies on this block of enum values being */ \ /* contiguous and sorted in the same order!*/ \ + T(AssemblyAssign, ":=", 2) \ T(Assign, "=", 2) \ /* The following have to be in exactly the same order as the simple binary operators*/ \ T(AssignBitOr, "|=", 2) \ diff --git a/libyul/AsmParser.cpp b/libyul/AsmParser.cpp index 217c838a712b..3c52cfe95702 100644 --- a/libyul/AsmParser.cpp +++ b/libyul/AsmParser.cpp @@ -158,22 +158,21 @@ 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: case Token::Colon: { if (elementary.type() != typeid(Identifier)) fatalParserError("Label name / variable 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) + if (currentToken() == Token::AssemblyAssign && peekNextToken() != Token::Colon) { Assignment assignment = createWithLocation(identifier.location); if (m_dialect->builtin(identifier.name)) @@ -188,6 +187,9 @@ Statement Parser::parseStatement() } else { + if (currentToken() == Token::Colon) + advance(); + // label if (m_dialect->flavour != AsmFlavour::Loose) fatalParserError("Labels are not supported."); @@ -439,10 +441,9 @@ VariableDeclaration Parser::parseVariableDeclaration() else break; } - if (currentToken() == Token::Colon) + if (currentToken() == Token::AssemblyAssign) { - expectToken(Token::Colon); - expectToken(Token::Assign); + expectToken(Token::AssemblyAssign); varDecl.value = make_unique(parseExpression()); varDecl.location.end = locationOf(*varDecl.value).end; } diff --git a/test/libsolidity/syntaxTests/inlineAssembly/invalid/missing_variable_in_assign.sol b/test/libsolidity/syntaxTests/inlineAssembly/invalid/missing_variable_in_assign.sol index c898433340dc..84d72c2d4091 100644 --- a/test/libsolidity/syntaxTests/inlineAssembly/invalid/missing_variable_in_assign.sol +++ b/test/libsolidity/syntaxTests/inlineAssembly/invalid/missing_variable_in_assign.sol @@ -7,5 +7,5 @@ contract C { } } // ---- -// ParserError: (87-88): Literal, identifier or instruction expected. -// ParserError: (87-88): Expected primary expression. +// ParserError: (87-89): Literal, identifier or instruction expected. +// ParserError: (87-89): Expected primary expression. diff --git a/test/libsolidity/syntaxTests/inlineAssembly/invalid/whitespace_in_assignment.sol b/test/libsolidity/syntaxTests/inlineAssembly/invalid/whitespace_in_assignment.sol new file mode 100644 index 000000000000..e3444b3894fe --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/invalid/whitespace_in_assignment.sol @@ -0,0 +1,10 @@ +contract C { + function f() public pure { + assembly { + let x : = mload(0) + } + } +} +// ---- +// ParserError: (69-70): Literal, identifier or instruction expected. +// ParserError: (69-70): Expected primary expression.